@manuscripts/body-editor 3.12.66 → 3.13.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/dist/cjs/components/toolbar/type-selector/styles.js +2 -1
- package/dist/cjs/versions.js +1 -1
- package/dist/es/components/toolbar/type-selector/styles.js +2 -1
- package/dist/es/versions.js +1 -1
- package/dist/types/components/toolbar/type-selector/styles.d.ts +2 -2
- package/dist/types/lib/footnotes.d.ts +4 -2
- package/dist/types/lib/utils.d.ts +5 -4
- package/dist/types/versions.d.ts +1 -1
- package/package.json +37 -36
- package/{dist/es/lib/statistics.js → src/__mocks__/styleMock.ts} +2 -14
- package/src/assets.ts +20 -0
- package/src/classes/collabProvider.ts +38 -0
- package/src/clipboard.ts +54 -0
- package/src/commands.ts +2109 -0
- package/src/components/ChangeHandlingForm.tsx +54 -0
- package/src/components/LanguageDropdown/index.tsx +343 -0
- package/src/components/affiliations/AffiliationForm.tsx +238 -0
- package/src/components/affiliations/AffiliationItem.tsx +151 -0
- package/src/components/affiliations/AffiliationList.tsx +71 -0
- package/src/components/affiliations/AffiliationsModal.tsx +676 -0
- package/src/components/affiliations/AffiliationsPanel.tsx +76 -0
- package/src/components/affiliations/CreateAffiliationModal.tsx +135 -0
- package/src/components/authors/AuthorDetailsForm.tsx +438 -0
- package/src/components/authors/AuthorList.tsx +81 -0
- package/src/components/authors/AuthorsModal.tsx +642 -0
- package/src/components/authors/AuthorsPanel.tsx +69 -0
- package/src/components/authors/CreateAuthorModal.tsx +172 -0
- package/src/components/authors/CreditDrawer.tsx +71 -0
- package/src/components/authors/DraggableAuthor.tsx +228 -0
- package/src/components/authors/useManageAffiliations.tsx +77 -0
- package/src/components/authors/useManageCredit.tsx +63 -0
- package/src/components/authors-affiliations/AuthorsAndAffiliationsModals.tsx +170 -0
- package/src/components/authors-affiliations/GenericPanel.tsx +164 -0
- package/src/components/authors-affiliations/ModalTabs.tsx +100 -0
- package/src/components/awards/AwardForm.tsx +338 -0
- package/src/components/awards/AwardModal.tsx +120 -0
- package/src/components/awards/DeleteAwardDiaolog.tsx +52 -0
- package/src/components/dialog/ConfirmationDialog.tsx +131 -0
- package/src/components/form/CreateModalStyles.tsx +37 -0
- package/src/components/form/FormFooter.tsx +54 -0
- package/src/components/form/FormPlaceholder.tsx +71 -0
- package/src/components/form/ModalFormActions.tsx +88 -0
- package/src/components/form/UnsavedLabel.tsx +49 -0
- package/src/components/hooks/use-debounce.ts +56 -0
- package/src/components/hooks/useAffiliationShowsErrorIndicator.ts +51 -0
- package/src/components/hooks/useAuthorShowsErrorIndicator.ts +73 -0
- package/src/components/keyboard-shortcuts-modal/FormattedShortcut.tsx +56 -0
- package/src/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.tsx +283 -0
- package/src/components/keyboard-shortcuts-modal/keyboard-shortcuts.ts +304 -0
- package/src/components/keywords/AddKeywordInline.tsx +284 -0
- package/src/components/keywords/DeleteKeywordDialog.tsx +52 -0
- package/src/components/modal-drawer/GenericDrawer.tsx +65 -0
- package/src/components/modal-drawer/GenericDrawerGroup.tsx +125 -0
- package/src/components/outline/DraggableTree.tsx +438 -0
- package/src/components/outline/ManuscriptOutline.tsx +127 -0
- package/src/components/outline/Outline.tsx +141 -0
- package/src/components/references/BibliographyItemSource.ts +80 -0
- package/src/components/references/CitationEditor.tsx +301 -0
- package/src/components/references/CitationViewer.tsx +62 -0
- package/src/components/references/ImportBibliographyForm.tsx +232 -0
- package/src/components/references/ImportBibliographyModal.tsx +159 -0
- package/src/components/references/ReferenceForm/PersonDropDown.tsx +93 -0
- package/src/components/references/ReferenceForm/ReferenceForm.tsx +701 -0
- package/src/components/references/ReferenceForm/config.ts +133 -0
- package/src/components/references/ReferenceForm/styled-components.ts +156 -0
- package/src/components/references/ReferenceLine.tsx +43 -0
- package/src/components/references/ReferenceSearch.tsx +163 -0
- package/src/components/references/ReferenceSearchResults.tsx +113 -0
- package/src/components/references/ReferenceSearchResultsPlaceholder.tsx +71 -0
- package/src/components/references/ReferenceSearchSection.tsx +124 -0
- package/src/components/references/ReferencesEditor.tsx +61 -0
- package/src/components/references/ReferencesModal.tsx +352 -0
- package/src/components/references/SearchInput.tsx +98 -0
- package/src/components/toolbar/InsertEmbedDialog.tsx +222 -0
- package/src/components/toolbar/InsertTableDialog.tsx +208 -0
- package/src/components/toolbar/ListMenuItem.tsx +203 -0
- package/src/components/toolbar/helpers.ts +547 -0
- package/src/components/toolbar/type-selector/OptionComponent.tsx +89 -0
- package/src/components/toolbar/type-selector/TypeSelector.tsx +157 -0
- package/src/components/toolbar/type-selector/styles.ts +79 -0
- package/src/components/views/CrossReferenceItems.tsx +199 -0
- package/src/components/views/DeleteEmbedDialog.tsx +83 -0
- package/src/components/views/DeleteFootnoteDialog.tsx +54 -0
- package/src/components/views/FigureDropdown.tsx +423 -0
- package/src/components/views/FootnotesSelector.tsx +255 -0
- package/src/components/views/InsertSpecialCharacter.tsx +245 -0
- package/src/components/views/LinkForm.tsx +220 -0
- package/src/components/views/TableCellContextMenu.tsx +241 -0
- package/src/configs/ManuscriptsEditor.ts +140 -0
- package/src/configs/editor-plugins.ts +119 -0
- package/src/configs/editor-views.ts +139 -0
- package/src/icons.ts +62 -0
- package/src/index.ts +65 -0
- package/src/keys/highlight.ts +65 -0
- package/src/keys/index.ts +33 -0
- package/src/keys/keyword.ts +69 -0
- package/src/keys/list.ts +156 -0
- package/src/keys/misc.ts +112 -0
- package/src/keys/title.ts +221 -0
- package/src/lib/__tests__/__fixtures__/doc.json +388 -0
- package/src/lib/__tests__/__snapshots__/paste.test.ts.snap +24 -0
- package/src/lib/__tests__/authors.test.ts +202 -0
- package/src/lib/__tests__/helpers.test.ts +46 -0
- package/src/lib/__tests__/paste.test.ts +57 -0
- package/src/lib/__tests__/plugins.test.ts +176 -0
- package/src/lib/__tests__/url.test.ts +31 -0
- package/src/lib/array-reducer.ts +68 -0
- package/src/lib/authors-and-affiliations.ts +81 -0
- package/src/lib/authors.ts +67 -0
- package/src/lib/capabilities.ts +55 -0
- package/src/lib/codemirror.ts +37 -0
- package/src/lib/comments.ts +123 -0
- package/src/lib/context-menu.ts +745 -0
- package/src/lib/copy.ts +30 -0
- package/src/lib/crossref.ts +90 -0
- package/src/lib/dnd.ts +29 -0
- package/src/lib/doc.ts +167 -0
- package/src/lib/dompurify.ts +28 -0
- package/src/lib/files.ts +180 -0
- package/src/lib/footnotes.ts +83 -0
- package/src/lib/get-media-type.ts +105 -0
- package/src/lib/helpers.ts +199 -0
- package/src/lib/hierarchy.ts +117 -0
- package/src/lib/languages.ts +37 -0
- package/src/lib/lists.ts +56 -0
- package/src/lib/math.ts +111 -0
- package/src/lib/media.ts +334 -0
- package/src/lib/navigation-utils.ts +235 -0
- package/src/lib/normalize.ts +70 -0
- package/src/lib/paste.ts +304 -0
- package/src/lib/placeholder.ts +32 -0
- package/src/lib/platform.ts +18 -0
- package/src/lib/plugins.ts +22 -0
- package/src/lib/popper.ts +180 -0
- package/src/lib/position-menu.ts +184 -0
- package/src/lib/references.ts +94 -0
- package/src/lib/template.ts +29 -0
- package/src/lib/track-changes-utils.ts +34 -0
- package/{dist/types/lib/statistics.d.ts → src/lib/url.ts} +11 -8
- package/src/lib/use-do-with-debounce.ts +39 -0
- package/src/lib/utils.ts +323 -0
- package/src/lib/view.ts +100 -0
- package/src/menus.tsx +684 -0
- package/src/node-type-icons.tsx +83 -0
- package/src/plugins/__tests__/__fixtures__/deleted-footnote.json +140 -0
- package/src/plugins/__tests__/__fixtures__/inserted-footnote.json +153 -0
- package/src/plugins/__tests__/footnotes.test.ts +67 -0
- package/src/plugins/accessibility_element.ts +219 -0
- package/src/plugins/add-subtitle.ts +102 -0
- package/src/plugins/affiliations.ts +136 -0
- package/src/plugins/alt-titles.ts +219 -0
- package/src/plugins/bibliography.ts +235 -0
- package/src/plugins/comments.ts +328 -0
- package/src/plugins/cross-references.ts +70 -0
- package/src/plugins/detect-inconsistency/detect-inconsistency-utils.ts +102 -0
- package/src/plugins/detect-inconsistency/index.ts +55 -0
- package/src/plugins/detect-inconsistency/validators.ts +283 -0
- package/src/plugins/doi.ts +66 -0
- package/src/plugins/editor-props.ts +39 -0
- package/src/plugins/elements.ts +60 -0
- package/src/plugins/footnotes.ts +298 -0
- package/src/plugins/link.ts +53 -0
- package/src/plugins/lock-body.ts +136 -0
- package/src/plugins/move-node.ts +55 -0
- package/src/plugins/objects.ts +125 -0
- package/src/plugins/paragraphs.ts +90 -0
- package/src/plugins/persist.ts +64 -0
- package/src/plugins/persistent-cursor.ts +66 -0
- package/src/plugins/placeholder.ts +219 -0
- package/src/plugins/prevent-empty.ts +50 -0
- package/src/plugins/search-replace/index.ts +157 -0
- package/src/plugins/search-replace/lib.ts +95 -0
- package/src/plugins/section_category.ts +212 -0
- package/src/plugins/section_title/autocompletion.ts +87 -0
- package/src/plugins/section_title/index.ts +105 -0
- package/src/plugins/selected-suggestion.ts +243 -0
- package/src/plugins/tables-cursor-fix.ts +143 -0
- package/src/plugins/translations.ts +263 -0
- package/src/rules.ts +60 -0
- package/src/selection.ts +112 -0
- package/src/testing/default-capabilities.ts +48 -0
- package/src/testing/default-editor-data.ts +73 -0
- package/src/testing/empty-editor-doc.json +62 -0
- package/src/testing/polyfill-dom.ts +43 -0
- package/src/testing/section-categories.json +161 -0
- package/src/testing/setup-editor.ts +55 -0
- package/src/tests.ts +42 -0
- package/src/toolbar.tsx +259 -0
- package/src/types/@citation-js/core.d.ts +16 -0
- package/src/types/@citation-js/index.d.ts +16 -0
- package/src/types/@citation-js/plugin-bibtex.d.ts +16 -0
- package/src/types/@citation-js/plugin-csl.d.ts +16 -0
- package/src/types/@citation-js/plugin-doi.d.ts +16 -0
- package/src/types/@citation-js/plugin-enw.d.ts +16 -0
- package/src/types/@citation-js/plugin-pubmed.d.ts +16 -0
- package/src/types/@citation-js/plugin-ris.d.ts +16 -0
- package/src/types/citeproc.d.ts +124 -0
- package/src/types/css.d.ts +16 -0
- package/src/types/json.d.ts +17 -0
- package/src/types/prosemirror-dev-tools.d.ts +16 -0
- package/src/types/prosemirror-dropcursor.d.ts +16 -0
- package/src/types/styled-components.d.ts +23 -0
- package/src/types.ts +49 -0
- package/src/useEditor.ts +244 -0
- package/src/versions.ts +3 -0
- package/src/views/ReactSubView.tsx +145 -0
- package/src/views/abstracts.ts +46 -0
- package/src/views/accessibility_element.ts +86 -0
- package/src/views/affiliations.ts +254 -0
- package/src/views/alt_title.ts +85 -0
- package/src/views/alt_titles_section.ts +97 -0
- package/src/views/attachment.ts +160 -0
- package/src/views/attachments.ts +72 -0
- package/src/views/author_notes.ts +96 -0
- package/src/views/award.ts +194 -0
- package/src/views/awards.ts +59 -0
- package/src/views/base_node_view.ts +85 -0
- package/src/views/bibliography_element.ts +313 -0
- package/src/views/block_view.ts +100 -0
- package/src/views/blockquote_element.ts +26 -0
- package/src/views/blockquote_element_editable.ts +24 -0
- package/src/views/box_element.ts +33 -0
- package/src/views/caption.ts +37 -0
- package/src/views/caption_title.ts +33 -0
- package/src/views/citation.ts +67 -0
- package/src/views/citation_editable.ts +312 -0
- package/src/views/contributors.ts +341 -0
- package/src/views/creators.ts +82 -0
- package/src/views/cross_reference.ts +74 -0
- package/src/views/cross_reference_editable.ts +113 -0
- package/src/views/editable_block.ts +141 -0
- package/src/views/embed.ts +345 -0
- package/src/views/empty.ts +26 -0
- package/src/views/equation.ts +47 -0
- package/src/views/equation_editable.ts +84 -0
- package/src/views/equation_element.ts +29 -0
- package/src/views/equation_element_editable.ts +21 -0
- package/src/views/figure.ts +84 -0
- package/src/views/figure_editable.ts +361 -0
- package/src/views/figure_element.ts +197 -0
- package/src/views/figure_element_editable.ts +21 -0
- package/src/views/footnote.ts +236 -0
- package/src/views/footnotes_element.ts +54 -0
- package/src/views/general_table_footnote.ts +140 -0
- package/src/views/hero_image.ts +76 -0
- package/src/views/hero_image_editable.ts +21 -0
- package/src/views/image_element.ts +373 -0
- package/src/views/image_element_editable.ts +21 -0
- package/src/views/inline_equation.ts +47 -0
- package/src/views/inline_equation_editable.ts +70 -0
- package/src/views/inline_footnote.ts +264 -0
- package/src/views/inline_footnote_editable.ts +20 -0
- package/src/views/keyword.ts +127 -0
- package/src/views/keyword_group.ts +109 -0
- package/src/views/link.ts +27 -0
- package/src/views/link_editable.ts +169 -0
- package/src/views/list.ts +46 -0
- package/src/views/list_item.ts +26 -0
- package/src/views/paragraph.ts +26 -0
- package/src/views/paragraph_editable.ts +21 -0
- package/src/views/placeholder.ts +35 -0
- package/src/views/placeholder_element.ts +38 -0
- package/src/views/placeholder_element_editable.ts +21 -0
- package/src/views/pullquote_element.ts +106 -0
- package/src/views/pullquote_element_editable.ts +24 -0
- package/src/views/quote_image_editable.ts +84 -0
- package/src/views/section.ts +64 -0
- package/src/views/section_label.ts +20 -0
- package/src/views/section_title.ts +87 -0
- package/src/views/section_title_editable.ts +21 -0
- package/src/views/subtitle.ts +42 -0
- package/src/views/subtitle_editable.ts +20 -0
- package/src/views/subtitles.ts +34 -0
- package/src/views/subtitles_editable.ts +21 -0
- package/src/views/supplement.ts +236 -0
- package/src/views/supplement_editable.ts +20 -0
- package/src/views/supplements.ts +65 -0
- package/src/views/supplements_editable.ts +21 -0
- package/src/views/table_cell.ts +150 -0
- package/src/views/table_element.ts +33 -0
- package/src/views/table_element_editable.ts +21 -0
- package/src/views/table_element_footer.ts +41 -0
- package/src/views/title.ts +46 -0
- package/src/views/title_editable.ts +20 -0
- package/src/views/trans_graphical_abstract.ts +55 -0
- package/src/views/trans_graphical_abstract_editable.ts +21 -0
- package/src/views/translated_abstract.ts +53 -0
- package/src/views/translated_abstract_editable.ts +21 -0
- package/dist/cjs/lib/statistics.js +0 -38
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { schema } from '@manuscripts/transform'
|
|
18
|
+
import { Slice } from 'prosemirror-model'
|
|
19
|
+
|
|
20
|
+
import { transformPasted } from '../paste'
|
|
21
|
+
|
|
22
|
+
test('transformPasted handler', () => {
|
|
23
|
+
const slice = Slice.fromJSON(schema, {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: 'paragraph',
|
|
27
|
+
attrs: {},
|
|
28
|
+
content: [{ type: 'hard_break' }],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: 'paragraph',
|
|
32
|
+
attrs: {
|
|
33
|
+
id: 'p-1',
|
|
34
|
+
},
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: 'These rhythmic patterns then sum together to create the signals that muscles need to carry out the movements.',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
openStart: 1,
|
|
44
|
+
openEnd: 1,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
expect(slice.content.childCount).toBe(2)
|
|
48
|
+
expect(slice.content.child(1).attrs.id).toBe('p-1')
|
|
49
|
+
|
|
50
|
+
const result = transformPasted(slice)
|
|
51
|
+
|
|
52
|
+
expect(result.content.childCount).toBe(1)
|
|
53
|
+
expect(result.content.size).toBe(111)
|
|
54
|
+
expect(slice.content.child(0).attrs.id).toBeNull()
|
|
55
|
+
|
|
56
|
+
expect(result).toMatchSnapshot('transform-pasted')
|
|
57
|
+
})
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import {
|
|
17
|
+
ActualManuscriptNode,
|
|
18
|
+
schema,
|
|
19
|
+
SectionCategory,
|
|
20
|
+
UserProfile,
|
|
21
|
+
} from '@manuscripts/transform'
|
|
22
|
+
import { createMemoryHistory } from 'history'
|
|
23
|
+
import { EditorState } from 'prosemirror-state'
|
|
24
|
+
import { EditorView } from 'prosemirror-view'
|
|
25
|
+
|
|
26
|
+
import plugins from '../../configs/editor-plugins'
|
|
27
|
+
import { EditorProps } from '../../configs/ManuscriptsEditor'
|
|
28
|
+
import { defaultCapabilities } from '../../testing/default-capabilities'
|
|
29
|
+
import sectionCategories from '../../testing/section-categories.json'
|
|
30
|
+
import { PopperManager } from '../popper'
|
|
31
|
+
import { getMatchingDescendant } from '../utils'
|
|
32
|
+
import jsonDoc from './__fixtures__/doc.json'
|
|
33
|
+
const userProfile: UserProfile = {
|
|
34
|
+
_id: 'MPUserProfile:1',
|
|
35
|
+
userID: 'MPUser:1',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const history = createMemoryHistory()
|
|
39
|
+
|
|
40
|
+
const buildProps = (doc: ActualManuscriptNode): EditorProps => ({
|
|
41
|
+
doc,
|
|
42
|
+
locale: 'en-US',
|
|
43
|
+
popper: new PopperManager(),
|
|
44
|
+
projectID: '',
|
|
45
|
+
getCurrentUser: () => userProfile,
|
|
46
|
+
history,
|
|
47
|
+
setComment: () => undefined,
|
|
48
|
+
setSelectedComment: () => undefined,
|
|
49
|
+
setEditorSelectedSuggestion: () => undefined,
|
|
50
|
+
theme: {},
|
|
51
|
+
getFiles: () => [],
|
|
52
|
+
fileManagement: {
|
|
53
|
+
download: () => undefined, // eslint-disable-line @typescript-eslint/no-empty-function
|
|
54
|
+
//@ts-ignore
|
|
55
|
+
upload: () => undefined, // eslint-disable-line @typescript-eslint/no-empty-function
|
|
56
|
+
},
|
|
57
|
+
getCapabilities: () => defaultCapabilities,
|
|
58
|
+
cslProps: {
|
|
59
|
+
style: '',
|
|
60
|
+
locale: '',
|
|
61
|
+
},
|
|
62
|
+
sectionCategories: new Map(
|
|
63
|
+
sectionCategories.map((category: SectionCategory) => [
|
|
64
|
+
category.id,
|
|
65
|
+
category,
|
|
66
|
+
])
|
|
67
|
+
),
|
|
68
|
+
fetchOEmbedHtml: async () => undefined,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe('editor view', () => {
|
|
72
|
+
const doc = schema.nodeFromJSON(jsonDoc) as ActualManuscriptNode
|
|
73
|
+
beforeAll(() => {
|
|
74
|
+
const root = document.createElement('div')
|
|
75
|
+
root.id = 'root'
|
|
76
|
+
window.document.body.appendChild(root)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test('loads without plugins', () => {
|
|
80
|
+
const state = EditorState.create({
|
|
81
|
+
doc,
|
|
82
|
+
schema,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const view = new EditorView(null, { state })
|
|
86
|
+
|
|
87
|
+
view.dispatch(view.state.tr.setMeta('update', true)) // trigger plugins
|
|
88
|
+
|
|
89
|
+
const emptySection = view.state.doc.child(2).child(0)
|
|
90
|
+
expect(emptySection.attrs.id).toBe('empty-section-1')
|
|
91
|
+
expect(emptySection.childCount).toBe(1)
|
|
92
|
+
|
|
93
|
+
const sectionWithEmptyParagraphs = view.state.doc.child(2).child(3)
|
|
94
|
+
expect(sectionWithEmptyParagraphs.attrs.id).toBe(
|
|
95
|
+
'section-with-empty-paragraphs-1'
|
|
96
|
+
)
|
|
97
|
+
expect(sectionWithEmptyParagraphs.childCount).toBe(3)
|
|
98
|
+
|
|
99
|
+
const sectionWithList = view.state.doc.child(2).child(6)
|
|
100
|
+
expect(sectionWithList.attrs.id).toBe('section-with-list')
|
|
101
|
+
expect(sectionWithList.childCount).toBe(2)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
test('loads with plugins', () => {
|
|
105
|
+
const state = EditorState.create({
|
|
106
|
+
doc,
|
|
107
|
+
schema,
|
|
108
|
+
plugins: plugins(buildProps(doc)),
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const view = new EditorView(null, { state })
|
|
112
|
+
|
|
113
|
+
view.dispatch(view.state.tr.setMeta('INIT', true)) // trigger plugins
|
|
114
|
+
|
|
115
|
+
const sectionWithEmptyParagraphs = view.state.doc.child(2).child(3)
|
|
116
|
+
expect(sectionWithEmptyParagraphs.attrs.id).toBe(
|
|
117
|
+
'section-with-empty-paragraphs-1'
|
|
118
|
+
)
|
|
119
|
+
expect(sectionWithEmptyParagraphs.childCount).toBe(2)
|
|
120
|
+
expect(sectionWithEmptyParagraphs.content.child(0).type).toBe(
|
|
121
|
+
schema.nodes.section_title
|
|
122
|
+
)
|
|
123
|
+
expect(sectionWithEmptyParagraphs.content.child(1).type).toBe(
|
|
124
|
+
schema.nodes.paragraph
|
|
125
|
+
)
|
|
126
|
+
expect(sectionWithEmptyParagraphs.content.child(1).textContent).toBe('')
|
|
127
|
+
|
|
128
|
+
const sectionWithList = view.state.doc.child(2).child(6)
|
|
129
|
+
expect(sectionWithList.attrs.id).toBe('section-with-list')
|
|
130
|
+
expect(sectionWithList.childCount).toBe(2)
|
|
131
|
+
expect(sectionWithList.content.child(0).type).toBe(
|
|
132
|
+
sectionWithList.type.schema.nodes.section_title
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const orderedList = sectionWithList.content.child(1)
|
|
136
|
+
expect(orderedList.type).toBe(sectionWithList.type.schema.nodes.list)
|
|
137
|
+
expect(orderedList.textContent).toBe('Test ')
|
|
138
|
+
|
|
139
|
+
const inlineEquation = getMatchingDescendant(
|
|
140
|
+
orderedList,
|
|
141
|
+
(node) => node.type === node.type.schema.nodes.inline_equation
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
expect(inlineEquation).not.toBeUndefined()
|
|
145
|
+
|
|
146
|
+
const sectionWithFigure = view.state.doc.child(2).child(7)
|
|
147
|
+
expect(sectionWithFigure.attrs.id).toBe('section-with-figure')
|
|
148
|
+
expect(sectionWithFigure.childCount).toBe(2)
|
|
149
|
+
expect(sectionWithFigure.content.child(0).type).toBe(
|
|
150
|
+
schema.nodes.section_title
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const figureElement = sectionWithFigure.content.child(1)
|
|
154
|
+
expect(figureElement.childCount).toBe(5)
|
|
155
|
+
expect(figureElement.type).toBe(schema.nodes.figure_element)
|
|
156
|
+
expect(figureElement.content.child(0).type).toBe(schema.nodes.figure)
|
|
157
|
+
expect(figureElement.content.child(1).type).toBe(schema.nodes.caption)
|
|
158
|
+
|
|
159
|
+
const sectionWithTable = view.state.doc.child(2).child(8)
|
|
160
|
+
expect(sectionWithTable.attrs.id).toBe('section-with-table')
|
|
161
|
+
expect(sectionWithTable.childCount).toBe(2)
|
|
162
|
+
expect(sectionWithTable.content.child(0).type).toBe(
|
|
163
|
+
sectionWithTable.type.schema.nodes.section_title
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
const tableElement = sectionWithTable.content.child(1)
|
|
167
|
+
expect(tableElement.childCount).toBe(5)
|
|
168
|
+
expect(tableElement.type).toBe(tableElement.type.schema.nodes.table_element)
|
|
169
|
+
expect(tableElement.content.child(0).type).toBe(
|
|
170
|
+
tableElement.type.schema.nodes.caption_title
|
|
171
|
+
)
|
|
172
|
+
expect(tableElement.content.child(1).type).toBe(
|
|
173
|
+
tableElement.type.schema.nodes.table
|
|
174
|
+
)
|
|
175
|
+
})
|
|
176
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { allowedHref } from '../url'
|
|
18
|
+
|
|
19
|
+
describe('url', () => {
|
|
20
|
+
test('allows valid protocols', () => {
|
|
21
|
+
expect(allowedHref('http://example.com')).toBe(true)
|
|
22
|
+
expect(allowedHref('https://example.com')).toBe(true)
|
|
23
|
+
expect(allowedHref('ftp://example.com')).toBe(true)
|
|
24
|
+
expect(allowedHref(' http://example.com')).toBe(true) // leading space
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('rejects invalid protocols', () => {
|
|
28
|
+
expect(allowedHref('javascript:alert("hi")')).toBe(false)
|
|
29
|
+
expect(allowedHref('httpp://example.com')).toBe(false)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2024 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Attrs } from 'prosemirror-model'
|
|
18
|
+
|
|
19
|
+
export type Update<T> = {
|
|
20
|
+
type: 'update'
|
|
21
|
+
items: T[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type Delete<T> = {
|
|
25
|
+
type: 'delete'
|
|
26
|
+
item: T
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type Set<T> = {
|
|
30
|
+
type: 'set'
|
|
31
|
+
state: T[]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type Action<T> = Update<T> | Delete<T> | Set<T>
|
|
35
|
+
|
|
36
|
+
export const arrayReducer = <T>(
|
|
37
|
+
isEqual: (a: T, b: T) => boolean = (a, b) => a === b
|
|
38
|
+
) => {
|
|
39
|
+
return (state: T[], action: Action<T>): T[] => {
|
|
40
|
+
const handleUpdate = (state: T[], items: T[]): T[] => {
|
|
41
|
+
const copy = [...state]
|
|
42
|
+
items.forEach((item) => {
|
|
43
|
+
const index = copy.findIndex((i) => isEqual(item, i))
|
|
44
|
+
if (index >= 0) {
|
|
45
|
+
copy[index] = item
|
|
46
|
+
} else {
|
|
47
|
+
copy.push(item)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
return copy
|
|
51
|
+
}
|
|
52
|
+
const handleDelete = (state: T[], item: T): T[] => {
|
|
53
|
+
return state.filter((i) => !isEqual(item, i))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
switch (action.type) {
|
|
57
|
+
case 'update':
|
|
58
|
+
return handleUpdate(state, action.items)
|
|
59
|
+
case 'delete':
|
|
60
|
+
return handleDelete(state, action.item)
|
|
61
|
+
case 'set':
|
|
62
|
+
return action.state
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const attrsReducer = <T extends Attrs>() =>
|
|
68
|
+
arrayReducer<T>((a, b) => a.id === b.id)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
generateNodeID,
|
|
19
|
+
ManuscriptEditorView,
|
|
20
|
+
ManuscriptNodeType,
|
|
21
|
+
schema,
|
|
22
|
+
} from '@manuscripts/transform'
|
|
23
|
+
import { Attrs } from 'prosemirror-model'
|
|
24
|
+
|
|
25
|
+
import { AffiliationAttrs, ContributorAttrs } from './authors'
|
|
26
|
+
import { findInsertionPosition } from './utils'
|
|
27
|
+
import { findChildByType, updateNodeAttrs } from './view'
|
|
28
|
+
|
|
29
|
+
function insertNode(
|
|
30
|
+
parentType: ManuscriptNodeType,
|
|
31
|
+
childType: ManuscriptNodeType
|
|
32
|
+
) {
|
|
33
|
+
return (view: ManuscriptEditorView, attrs: Attrs) => {
|
|
34
|
+
const parent = findChildByType(view, parentType)
|
|
35
|
+
let tr = view.state.tr
|
|
36
|
+
|
|
37
|
+
if (parent) {
|
|
38
|
+
tr = tr.insert(parent.pos + 1, childType.create(attrs))
|
|
39
|
+
} else {
|
|
40
|
+
const insertPos = findInsertionPosition(parentType, view.state.doc)
|
|
41
|
+
const wrapper = parentType.create({
|
|
42
|
+
id: generateNodeID(parentType),
|
|
43
|
+
})
|
|
44
|
+
tr = tr
|
|
45
|
+
.insert(insertPos, wrapper)
|
|
46
|
+
.insert(insertPos + 1, childType.create(attrs))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
view.dispatch(tr)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function upsertNode<T extends Attrs>(
|
|
54
|
+
nodeType: ManuscriptNodeType,
|
|
55
|
+
insertFn: (view: ManuscriptEditorView, attrs: T) => void
|
|
56
|
+
) {
|
|
57
|
+
return (view: ManuscriptEditorView, attrs: T) => {
|
|
58
|
+
if (!updateNodeAttrs(view, nodeType, attrs)) {
|
|
59
|
+
insertFn(view, attrs)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const insertAuthorNode = insertNode(
|
|
65
|
+
schema.nodes.contributors,
|
|
66
|
+
schema.nodes.contributor
|
|
67
|
+
)
|
|
68
|
+
const insertAffiliationNode = insertNode(
|
|
69
|
+
schema.nodes.affiliations,
|
|
70
|
+
schema.nodes.affiliation
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
export const upsertAuthor = upsertNode<ContributorAttrs>(
|
|
74
|
+
schema.nodes.contributor,
|
|
75
|
+
insertAuthorNode
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
export const upsertAffiliation = upsertNode<AffiliationAttrs>(
|
|
79
|
+
schema.nodes.affiliation,
|
|
80
|
+
insertAffiliationNode
|
|
81
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { AffiliationNode, ContributorNode } from '@manuscripts/transform'
|
|
18
|
+
|
|
19
|
+
import { TrackableAttributes } from '../types'
|
|
20
|
+
|
|
21
|
+
export type AffiliationAttrs = TrackableAttributes<AffiliationNode>
|
|
22
|
+
export type ContributorAttrs = TrackableAttributes<ContributorNode>
|
|
23
|
+
|
|
24
|
+
export const affiliationLabel = (affiliation: AffiliationAttrs) => {
|
|
25
|
+
const institution = affiliation.institution
|
|
26
|
+
if (!institution) {
|
|
27
|
+
return '(unknown institution)'
|
|
28
|
+
}
|
|
29
|
+
const department = affiliation.department
|
|
30
|
+
return department ? `${institution} (${department})`.trim() : institution
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const affiliationName = (affiliation: AffiliationAttrs) => {
|
|
34
|
+
return [
|
|
35
|
+
affiliation.department,
|
|
36
|
+
affiliation.institution,
|
|
37
|
+
affiliation.addressLine1,
|
|
38
|
+
affiliation.city,
|
|
39
|
+
affiliation.county,
|
|
40
|
+
affiliation.country,
|
|
41
|
+
affiliation.postCode,
|
|
42
|
+
]
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join(', ')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const authorLabel = (author: ContributorAttrs) => {
|
|
48
|
+
const parts = [
|
|
49
|
+
author.prefix,
|
|
50
|
+
author.family ? initials(author) : author.given,
|
|
51
|
+
author.family,
|
|
52
|
+
author.suffix,
|
|
53
|
+
].filter(Boolean)
|
|
54
|
+
return parts.length ? parts.join(' ') : 'Unknown Author'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const initials = (contributor: ContributorAttrs): string =>
|
|
58
|
+
contributor.given
|
|
59
|
+
? contributor.given
|
|
60
|
+
.trim()
|
|
61
|
+
.split(' ')
|
|
62
|
+
.map((part) => part.substring(0, 1).toUpperCase() + '.')
|
|
63
|
+
.join('')
|
|
64
|
+
: ''
|
|
65
|
+
|
|
66
|
+
export const authorComparator = (a: ContributorAttrs, b: ContributorAttrs) =>
|
|
67
|
+
a.priority - b.priority
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2025 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export type Capabilities = {
|
|
18
|
+
/* track changes */
|
|
19
|
+
handleSuggestion: boolean
|
|
20
|
+
editWithoutTracking: boolean
|
|
21
|
+
rejectOwnSuggestion: boolean
|
|
22
|
+
|
|
23
|
+
/* comments */
|
|
24
|
+
handleOwnComments: boolean
|
|
25
|
+
resolveOwnComment: boolean
|
|
26
|
+
handleOthersComments: boolean
|
|
27
|
+
resolveOthersComment: boolean
|
|
28
|
+
createComment: boolean
|
|
29
|
+
|
|
30
|
+
/* file handling */
|
|
31
|
+
downloadFiles: boolean
|
|
32
|
+
changeDesignation: boolean
|
|
33
|
+
moveFile: boolean
|
|
34
|
+
replaceFile: boolean
|
|
35
|
+
uploadFile: boolean
|
|
36
|
+
detachFile: boolean
|
|
37
|
+
setMainManuscript: boolean
|
|
38
|
+
|
|
39
|
+
/* editor */
|
|
40
|
+
formatArticle: boolean
|
|
41
|
+
editArticle: boolean
|
|
42
|
+
editMetadata: boolean
|
|
43
|
+
editCitationsAndRefs: boolean
|
|
44
|
+
seeEditorToolbar: boolean
|
|
45
|
+
seeReferencesButtons: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export enum Actions {
|
|
49
|
+
// proceed = 'proceed',
|
|
50
|
+
updateAttachment = 'update-attachment',
|
|
51
|
+
updateDueDate = 'update-due-date',
|
|
52
|
+
addNote = 'add-note',
|
|
53
|
+
setMainManuscript = 'set-main-manuscript',
|
|
54
|
+
editWithoutTracking = 'edit-without-tracking',
|
|
55
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2019 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import 'codemirror/addon/display/placeholder'
|
|
18
|
+
import 'codemirror/lib/codemirror.css'
|
|
19
|
+
|
|
20
|
+
import CodeMirror from 'codemirror'
|
|
21
|
+
|
|
22
|
+
type CreateEditor = (
|
|
23
|
+
options: CodeMirror.EditorConfiguration
|
|
24
|
+
) => Promise<CodeMirror.Editor>
|
|
25
|
+
|
|
26
|
+
export const createEditor: CreateEditor = async (options) => {
|
|
27
|
+
return CodeMirror(
|
|
28
|
+
() => {
|
|
29
|
+
// no-op
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
...options,
|
|
33
|
+
lineNumbers: true,
|
|
34
|
+
lineWrapping: true,
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2024 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import {
|
|
17
|
+
CommentNode,
|
|
18
|
+
HighlightMarkerNode,
|
|
19
|
+
ManuscriptNode,
|
|
20
|
+
} from '@manuscripts/transform'
|
|
21
|
+
import { NodeWithPos } from 'prosemirror-utils'
|
|
22
|
+
import { EditorView } from 'prosemirror-view'
|
|
23
|
+
|
|
24
|
+
import { addNodeComment } from '../commands'
|
|
25
|
+
|
|
26
|
+
export type CommentAttrs = CommentNode['attrs']
|
|
27
|
+
export type HighlightMarkerAttrs = HighlightMarkerNode['attrs']
|
|
28
|
+
|
|
29
|
+
export type Comment = NodeComment | InlineComment
|
|
30
|
+
|
|
31
|
+
export type NodeComment = {
|
|
32
|
+
key: CommentKey
|
|
33
|
+
node: CommentNode
|
|
34
|
+
pos: number
|
|
35
|
+
target: NodeWithPos
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type InlineComment = {
|
|
39
|
+
key: CommentKey
|
|
40
|
+
node: CommentNode
|
|
41
|
+
pos: number
|
|
42
|
+
target: NodeWithPos
|
|
43
|
+
range: CommentRange
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type CommentRange = {
|
|
47
|
+
pos: number
|
|
48
|
+
size: number
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type CommentKey = string
|
|
52
|
+
|
|
53
|
+
export type CommentSelection = {
|
|
54
|
+
key: CommentKey
|
|
55
|
+
id: string
|
|
56
|
+
isNew: boolean
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
export const isNodeComment = (c: any): c is NodeComment => !c.range
|
|
61
|
+
|
|
62
|
+
export const isReply = (comment: Comment) =>
|
|
63
|
+
comment.node.attrs.target?.startsWith('MPComment')
|
|
64
|
+
|
|
65
|
+
export const getCommentKey = (
|
|
66
|
+
comment: CommentAttrs,
|
|
67
|
+
range: CommentRange | undefined,
|
|
68
|
+
target: ManuscriptNode
|
|
69
|
+
): CommentKey => {
|
|
70
|
+
if (!range) {
|
|
71
|
+
return target.attrs.id
|
|
72
|
+
} else if (!range.size) {
|
|
73
|
+
return `${target.attrs.id}-${range.pos}`
|
|
74
|
+
} else {
|
|
75
|
+
return comment.id
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const getCommentRange = (comment: CommentAttrs) => {
|
|
80
|
+
if (!comment.selector) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
pos: comment.selector.from,
|
|
85
|
+
size: comment.selector.to - comment.selector.from,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const createCommentMarker = (
|
|
90
|
+
tagName: string,
|
|
91
|
+
key: CommentKey,
|
|
92
|
+
count?: number
|
|
93
|
+
) => {
|
|
94
|
+
const element = document.createElement(tagName)
|
|
95
|
+
element.id = getMarkerID(key)
|
|
96
|
+
element.dataset.key = key
|
|
97
|
+
element.classList.add('comment-marker')
|
|
98
|
+
element.tabIndex = 0
|
|
99
|
+
|
|
100
|
+
if (count && count > 1) {
|
|
101
|
+
element.dataset.count = String(count)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
element.innerHTML = `
|
|
105
|
+
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
106
|
+
<path d="M4.0625 2.9375V7.3125L1.4375 11.6875H12.8125C13.7794 11.6875 14.5625 10.9044 14.5625 9.9375V2.9375C14.5625 1.97062 13.7794 1.1875 12.8125 1.1875H5.8125C4.84562 1.1875 4.0625 1.97062 4.0625 2.9375Z"
|
|
107
|
+
fill="#FFFCDB" stroke="#FFBD26" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
108
|
+
<path d="M6.6875 4.6875H11.9375" stroke="#FFBD26" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
109
|
+
<path d="M6.6875 8.1875H9.3125" stroke="#FFBD26" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
|
110
|
+
</svg>
|
|
111
|
+
`
|
|
112
|
+
return element
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const getMarkerID = (id: string) => {
|
|
116
|
+
return `${id}-comment-marker`
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const handleComment = (node: ManuscriptNode, view: EditorView): void => {
|
|
120
|
+
const { state } = view
|
|
121
|
+
|
|
122
|
+
addNodeComment(node, state, view.dispatch)
|
|
123
|
+
}
|