@manuscripts/body-editor 3.12.67 → 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,105 @@
|
|
|
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
|
+
interface MediaTypeInfo {
|
|
17
|
+
extension: string
|
|
18
|
+
isVideo: boolean
|
|
19
|
+
isAudio: boolean
|
|
20
|
+
isImage: boolean
|
|
21
|
+
isSupported: boolean
|
|
22
|
+
mimetype?: string
|
|
23
|
+
mimeSubtype?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const getMediaTypeInfo = (
|
|
27
|
+
filenameOrFile: string | File
|
|
28
|
+
): MediaTypeInfo => {
|
|
29
|
+
const filename =
|
|
30
|
+
typeof filenameOrFile === 'string'
|
|
31
|
+
? filenameOrFile
|
|
32
|
+
: filenameOrFile?.name || ''
|
|
33
|
+
const extension = filename.toLowerCase().split('.').pop()?.trim() || ''
|
|
34
|
+
|
|
35
|
+
const videoExtensions = new Set([
|
|
36
|
+
'mp4',
|
|
37
|
+
'webm',
|
|
38
|
+
'avi',
|
|
39
|
+
'mov',
|
|
40
|
+
'mkv',
|
|
41
|
+
'flv',
|
|
42
|
+
'wmv',
|
|
43
|
+
'mpg',
|
|
44
|
+
'mpeg',
|
|
45
|
+
])
|
|
46
|
+
const audioExtensions = new Set([
|
|
47
|
+
'mp3',
|
|
48
|
+
'wav',
|
|
49
|
+
'aac',
|
|
50
|
+
'ogg',
|
|
51
|
+
'flac',
|
|
52
|
+
'm4a',
|
|
53
|
+
'wma',
|
|
54
|
+
])
|
|
55
|
+
const imageExtensions = new Set([
|
|
56
|
+
'jpg',
|
|
57
|
+
'jpeg',
|
|
58
|
+
'png',
|
|
59
|
+
'gif',
|
|
60
|
+
'bmp',
|
|
61
|
+
'svg',
|
|
62
|
+
'webp',
|
|
63
|
+
'tiff',
|
|
64
|
+
'tif',
|
|
65
|
+
])
|
|
66
|
+
|
|
67
|
+
let mimetype: string | undefined
|
|
68
|
+
let mimeSubtype: string | undefined
|
|
69
|
+
|
|
70
|
+
if (typeof filenameOrFile !== 'string' && filenameOrFile?.type) {
|
|
71
|
+
const [type, subtype] = filenameOrFile.type.split('/')
|
|
72
|
+
if (type && subtype && ['video', 'audio', 'image'].includes(type)) {
|
|
73
|
+
mimetype = type
|
|
74
|
+
mimeSubtype = subtype
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!mimetype || !mimeSubtype) {
|
|
79
|
+
if (videoExtensions.has(extension)) {
|
|
80
|
+
mimetype = 'video'
|
|
81
|
+
mimeSubtype = extension === 'mov' ? 'quicktime' : extension
|
|
82
|
+
} else if (audioExtensions.has(extension)) {
|
|
83
|
+
mimetype = 'audio'
|
|
84
|
+
mimeSubtype = extension === 'm4a' ? 'mp4' : extension
|
|
85
|
+
} else if (imageExtensions.has(extension)) {
|
|
86
|
+
mimetype = 'image'
|
|
87
|
+
mimeSubtype = extension === 'jpg' ? 'jpeg' : extension
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const isVideo = mimetype === 'video' || videoExtensions.has(extension)
|
|
92
|
+
const isAudio = mimetype === 'audio' || audioExtensions.has(extension)
|
|
93
|
+
const isImage = mimetype === 'image' || imageExtensions.has(extension)
|
|
94
|
+
const isSupported = isVideo || isAudio || isImage
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
extension,
|
|
98
|
+
isVideo,
|
|
99
|
+
isAudio,
|
|
100
|
+
isImage,
|
|
101
|
+
isSupported,
|
|
102
|
+
mimetype,
|
|
103
|
+
mimeSubtype,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
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 {
|
|
18
|
+
isExecutableNodeType,
|
|
19
|
+
ManuscriptEditorState,
|
|
20
|
+
ManuscriptNode,
|
|
21
|
+
schema,
|
|
22
|
+
} from '@manuscripts/transform'
|
|
23
|
+
import { Node, ResolvedPos } from 'prosemirror-model'
|
|
24
|
+
import { NodeSelection, TextSelection } from 'prosemirror-state'
|
|
25
|
+
import { EditorView } from 'prosemirror-view'
|
|
26
|
+
|
|
27
|
+
export const isNodeOfType =
|
|
28
|
+
(...type: string[]) =>
|
|
29
|
+
(node: Node): boolean => {
|
|
30
|
+
const [head, ...tail] = type
|
|
31
|
+
if (node.type === node.type.schema.nodes[head]) {
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
if (tail && tail.length) {
|
|
35
|
+
return isNodeOfType(...tail)(node)
|
|
36
|
+
}
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const nearestAncestor =
|
|
41
|
+
(func: (node: ManuscriptNode) => boolean) =>
|
|
42
|
+
($pos: ResolvedPos): number | null => {
|
|
43
|
+
for (let d = $pos.depth; d >= 0; d--) {
|
|
44
|
+
if (func($pos.node(d))) {
|
|
45
|
+
return d
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// This function finds and merges similar items in an array.
|
|
52
|
+
// It uses a compare function to determine which items in the array
|
|
53
|
+
// are similar (or identical), and if a match is found, uses the mergeFunc
|
|
54
|
+
// to merge it with the match.
|
|
55
|
+
export const mergeSimilarItems =
|
|
56
|
+
<T>(compareFunc: (a: T, b: T) => boolean, mergeFunc: (a: T, b: T) => T) =>
|
|
57
|
+
(items: T[]): T[] => {
|
|
58
|
+
return items.reduce((acc: T[], item: T) => {
|
|
59
|
+
const existingIndex = acc.findIndex((existing) =>
|
|
60
|
+
compareFunc(existing, item)
|
|
61
|
+
)
|
|
62
|
+
if (existingIndex === -1) {
|
|
63
|
+
return [...acc, item]
|
|
64
|
+
}
|
|
65
|
+
return [
|
|
66
|
+
...acc.slice(0, existingIndex),
|
|
67
|
+
mergeFunc(acc[existingIndex], item),
|
|
68
|
+
...acc.slice(existingIndex + 1),
|
|
69
|
+
]
|
|
70
|
+
}, [])
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const selectionForOutlineNavigation = (
|
|
74
|
+
doc: Node,
|
|
75
|
+
pos: number
|
|
76
|
+
): NodeSelection | TextSelection => {
|
|
77
|
+
const node = doc.nodeAt(pos)
|
|
78
|
+
if (!node || isExecutableNodeType(node.type)) {
|
|
79
|
+
return NodeSelection.create(doc, pos)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (node.isTextblock) {
|
|
83
|
+
return TextSelection.create(doc, pos + 1)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (node.type === schema.nodes.section) {
|
|
87
|
+
let textPos: number | null = null
|
|
88
|
+
node.forEach((child, offset) => {
|
|
89
|
+
if (textPos !== null) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
child.type === schema.nodes.section_title ||
|
|
94
|
+
child.type === schema.nodes.section_title_plain
|
|
95
|
+
) {
|
|
96
|
+
textPos = pos + 1 + offset + 1
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
if (textPos !== null) {
|
|
100
|
+
return TextSelection.create(doc, textPos)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return NodeSelection.create(doc, pos)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const handleScrollToSelectedTarget = (view: EditorView): boolean => {
|
|
108
|
+
const selection = view.state.selection
|
|
109
|
+
if (selection.empty) {
|
|
110
|
+
return false
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const node = view.state.doc.nodeAt(selection.from)
|
|
114
|
+
if (!node) {
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let target: Element | null
|
|
119
|
+
|
|
120
|
+
//this is to support scrolling to nodes whose views are not managed by PM
|
|
121
|
+
if (node.attrs.id) {
|
|
122
|
+
target = view.dom.querySelector(`[id="${node.attrs.id}"]`)
|
|
123
|
+
} else {
|
|
124
|
+
let node = view.domAtPos(selection.from).node
|
|
125
|
+
|
|
126
|
+
const ELEMENT_NODE = 1
|
|
127
|
+
while (node.nodeType !== ELEMENT_NODE && node.parentElement) {
|
|
128
|
+
node = node.parentElement
|
|
129
|
+
}
|
|
130
|
+
target = node as Element
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!target || !(target instanceof HTMLElement)) {
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Set block alignment based on the node type
|
|
138
|
+
const blockAlignment =
|
|
139
|
+
node.type === schema.nodes.bibliography_item ? 'center' : 'start'
|
|
140
|
+
|
|
141
|
+
// Scroll the target element into view
|
|
142
|
+
target.scrollIntoView({
|
|
143
|
+
behavior: 'smooth',
|
|
144
|
+
block: blockAlignment,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Find the boundaries of the intended word based on the current cursor position
|
|
151
|
+
export const findWordBoundaries = (
|
|
152
|
+
state: ManuscriptEditorState,
|
|
153
|
+
position: number
|
|
154
|
+
) => {
|
|
155
|
+
let start = position
|
|
156
|
+
let end = position
|
|
157
|
+
const resolvedPos = state.doc.resolve(position)
|
|
158
|
+
const blockStart = resolvedPos.start()
|
|
159
|
+
const blockEnd = resolvedPos.end()
|
|
160
|
+
|
|
161
|
+
// Move backward to find the start of the word
|
|
162
|
+
while (
|
|
163
|
+
start > blockStart &&
|
|
164
|
+
!/\s/.test(state.doc.textBetween(start - 1, start))
|
|
165
|
+
) {
|
|
166
|
+
start--
|
|
167
|
+
}
|
|
168
|
+
// Move forward to find the end of the word
|
|
169
|
+
while (end < blockEnd && !/\s/.test(state.doc.textBetween(end, end + 1))) {
|
|
170
|
+
end++
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let from = start
|
|
174
|
+
let to = end
|
|
175
|
+
|
|
176
|
+
// If no word is found (cursor between spaces), search for the previous word
|
|
177
|
+
if (from === to) {
|
|
178
|
+
// Move backward through spaces
|
|
179
|
+
while (
|
|
180
|
+
start > blockStart &&
|
|
181
|
+
/\s/.test(state.doc.textBetween(start - 1, start))
|
|
182
|
+
) {
|
|
183
|
+
start--
|
|
184
|
+
}
|
|
185
|
+
to = start
|
|
186
|
+
|
|
187
|
+
// Move backward to find the start of the previous word
|
|
188
|
+
while (
|
|
189
|
+
start > blockStart &&
|
|
190
|
+
!/\s/.test(state.doc.textBetween(start - 1, start))
|
|
191
|
+
) {
|
|
192
|
+
start--
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
from = start
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return { from, to }
|
|
199
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
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 {
|
|
18
|
+
GROUP_LIST,
|
|
19
|
+
hasGroup,
|
|
20
|
+
isElementNodeType,
|
|
21
|
+
isSectionNodeType,
|
|
22
|
+
ManuscriptEditorState,
|
|
23
|
+
ManuscriptNode,
|
|
24
|
+
ManuscriptNodeType,
|
|
25
|
+
nodeNames,
|
|
26
|
+
} from '@manuscripts/transform'
|
|
27
|
+
import { ResolvedPos } from 'prosemirror-model'
|
|
28
|
+
|
|
29
|
+
import { Dispatch } from '../commands'
|
|
30
|
+
|
|
31
|
+
interface NodeWithPosition {
|
|
32
|
+
node: ManuscriptNode
|
|
33
|
+
before: number
|
|
34
|
+
after: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const isListNodeType = (nodeType: ManuscriptNodeType) =>
|
|
38
|
+
hasGroup(nodeType, GROUP_LIST)
|
|
39
|
+
|
|
40
|
+
export const findListParent = (
|
|
41
|
+
$pos: ResolvedPos
|
|
42
|
+
): NodeWithPosition | undefined => {
|
|
43
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
44
|
+
const node = $pos.node(depth)
|
|
45
|
+
|
|
46
|
+
if (isListNodeType(node.type)) {
|
|
47
|
+
return {
|
|
48
|
+
node,
|
|
49
|
+
before: $pos.before(depth),
|
|
50
|
+
after: $pos.after(depth),
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const findClosestParentElement = (
|
|
57
|
+
$pos: ResolvedPos
|
|
58
|
+
): NodeWithPosition | undefined => {
|
|
59
|
+
const listParent = findListParent($pos)
|
|
60
|
+
|
|
61
|
+
if (listParent) {
|
|
62
|
+
return listParent
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
66
|
+
const node = $pos.node(depth)
|
|
67
|
+
|
|
68
|
+
if (isSectionNodeType(node.type) || isElementNodeType(node.type)) {
|
|
69
|
+
return {
|
|
70
|
+
node,
|
|
71
|
+
before: $pos.before(depth),
|
|
72
|
+
after: $pos.after(depth),
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const findClosestParentElementNodeName = (
|
|
79
|
+
state: ManuscriptEditorState
|
|
80
|
+
): string => {
|
|
81
|
+
if (state.selection) {
|
|
82
|
+
const fromParentElement = findClosestParentElement(state.selection.$from)
|
|
83
|
+
const toParentElement = findClosestParentElement(state.selection.$to)
|
|
84
|
+
|
|
85
|
+
if (fromParentElement && toParentElement) {
|
|
86
|
+
if (fromParentElement.node === toParentElement.node) {
|
|
87
|
+
const nodeName = nodeNames.get(fromParentElement.node.type)
|
|
88
|
+
|
|
89
|
+
if (nodeName) {
|
|
90
|
+
return nodeName
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return ''
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const deleteClosestParentElement = (
|
|
100
|
+
state: ManuscriptEditorState,
|
|
101
|
+
dispatch?: Dispatch
|
|
102
|
+
) => {
|
|
103
|
+
if (state.selection) {
|
|
104
|
+
const fromParentElement = findClosestParentElement(state.selection.$from)
|
|
105
|
+
const toParentElement = findClosestParentElement(state.selection.$to)
|
|
106
|
+
|
|
107
|
+
if (dispatch) {
|
|
108
|
+
if (fromParentElement && toParentElement) {
|
|
109
|
+
dispatch(
|
|
110
|
+
state.tr.delete(fromParentElement.before, toParentElement.after)
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return true
|
|
115
|
+
}
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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 interface Language {
|
|
18
|
+
code: string
|
|
19
|
+
name: string
|
|
20
|
+
nativeName: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ENGLISH = {
|
|
24
|
+
code: 'en',
|
|
25
|
+
name: 'English',
|
|
26
|
+
nativeName: 'English',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const getLanguage = (code: string, languages: Language[]) => {
|
|
30
|
+
return languages.find((l) => l.code === code) || ENGLISH
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const getLanguageLabel = (language: Language) => {
|
|
34
|
+
return language.nativeName && language.nativeName !== language.name
|
|
35
|
+
? `${language.name} (${language.nativeName})`
|
|
36
|
+
: language.name
|
|
37
|
+
}
|
package/src/lib/lists.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
import { ListStyleType } from '@manuscripts/transform'
|
|
17
|
+
|
|
18
|
+
export const parseCssListStyleType = (style: string): ListStyleType => {
|
|
19
|
+
switch (style) {
|
|
20
|
+
case 'disc':
|
|
21
|
+
return 'bullet'
|
|
22
|
+
case 'decimal':
|
|
23
|
+
return 'order'
|
|
24
|
+
case 'lower-alpha':
|
|
25
|
+
return 'alpha-lower'
|
|
26
|
+
case 'upper-alpha':
|
|
27
|
+
return 'alpha-upper'
|
|
28
|
+
case 'lower-roman':
|
|
29
|
+
return 'roman-lower'
|
|
30
|
+
case 'upper-roman':
|
|
31
|
+
return 'roman-upper'
|
|
32
|
+
case 'none':
|
|
33
|
+
return 'simple'
|
|
34
|
+
default:
|
|
35
|
+
return 'simple'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const writeCssListStyleType = (type: ListStyleType) => {
|
|
40
|
+
switch (type) {
|
|
41
|
+
case 'bullet':
|
|
42
|
+
return 'disc'
|
|
43
|
+
case 'order':
|
|
44
|
+
return 'decimal'
|
|
45
|
+
case 'alpha-lower':
|
|
46
|
+
return 'lower-alpha'
|
|
47
|
+
case 'alpha-upper':
|
|
48
|
+
return 'upper-alpha'
|
|
49
|
+
case 'roman-lower':
|
|
50
|
+
return 'lower-roman'
|
|
51
|
+
case 'roman-upper':
|
|
52
|
+
return 'upper-roman'
|
|
53
|
+
case 'simple':
|
|
54
|
+
return 'none'
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/lib/math.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
/**
|
|
18
|
+
* The versions file is generated at build time using
|
|
19
|
+
* the `versions.mjs` script.
|
|
20
|
+
*/
|
|
21
|
+
//@ts-ignore
|
|
22
|
+
//eslint-disable-next-line import/no-unresolved
|
|
23
|
+
import { MATHJAX_VERSION } from '../versions'
|
|
24
|
+
|
|
25
|
+
const src = `https://cdn.jsdelivr.net/npm/mathjax@${MATHJAX_VERSION}/es5/tex-svg.js`
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* MathJax uses delimiters to find math in the doc by default, which is
|
|
29
|
+
* not what we want. This will override that behavior and will instead
|
|
30
|
+
* look for equation nodes, and is based on the
|
|
31
|
+
* [MathJax upgrade guide](https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html).
|
|
32
|
+
*/
|
|
33
|
+
//@ts-ignore
|
|
34
|
+
const findMath = (doc) => {
|
|
35
|
+
let nodes = doc.options.elements
|
|
36
|
+
if (!nodes) {
|
|
37
|
+
nodes = doc.document.querySelectorAll('.equation')
|
|
38
|
+
}
|
|
39
|
+
for (const node of nodes) {
|
|
40
|
+
const math = new doc.options.MathItem(
|
|
41
|
+
node.textContent,
|
|
42
|
+
doc.inputJax[0],
|
|
43
|
+
node.tagName !== 'SPAN'
|
|
44
|
+
)
|
|
45
|
+
const text = document.createTextNode('')
|
|
46
|
+
node.innerHTML = ''
|
|
47
|
+
node.appendChild(text)
|
|
48
|
+
math.start = { node: text, delim: '', n: 0 }
|
|
49
|
+
math.end = { node: text, delim: '', n: 0 }
|
|
50
|
+
doc.math.push(math)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const config = {
|
|
55
|
+
options: {
|
|
56
|
+
renderActions: {
|
|
57
|
+
find: [10, findMath, ''],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const initMathJax = () => {
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
window.MathJax = config
|
|
65
|
+
const script = document.createElement('script')
|
|
66
|
+
script.src = src
|
|
67
|
+
script.async = true
|
|
68
|
+
document.head.appendChild(script)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const renderMath = (node: HTMLElement) => {
|
|
72
|
+
/* eslint-disable */
|
|
73
|
+
//@ts-ignore
|
|
74
|
+
if (!window.MathJax) {
|
|
75
|
+
initMathJax()
|
|
76
|
+
}
|
|
77
|
+
//@ts-ignore
|
|
78
|
+
if (window.MathJax.typeset) {
|
|
79
|
+
//@ts-ignore
|
|
80
|
+
if (!node.parentNode) {
|
|
81
|
+
awaitMounting(node).then(() => {
|
|
82
|
+
//@ts-ignore
|
|
83
|
+
window.MathJax.typeset([node])
|
|
84
|
+
})
|
|
85
|
+
} else {
|
|
86
|
+
//@ts-ignore
|
|
87
|
+
window.MathJax.typeset([node])
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/* eslint-enable */
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function awaitMounting(node: HTMLElement) {
|
|
94
|
+
return new Promise<void>(function (resolve, reject) {
|
|
95
|
+
let max = 10
|
|
96
|
+
function wait() {
|
|
97
|
+
max--
|
|
98
|
+
if (!node.parentNode) {
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
wait()
|
|
101
|
+
}, 0)
|
|
102
|
+
} else {
|
|
103
|
+
resolve()
|
|
104
|
+
}
|
|
105
|
+
if (max <= 0) {
|
|
106
|
+
reject()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
wait()
|
|
110
|
+
})
|
|
111
|
+
}
|