@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.
Files changed (289) hide show
  1. package/dist/cjs/components/toolbar/type-selector/styles.js +2 -1
  2. package/dist/cjs/versions.js +1 -1
  3. package/dist/es/components/toolbar/type-selector/styles.js +2 -1
  4. package/dist/es/versions.js +1 -1
  5. package/dist/types/components/toolbar/type-selector/styles.d.ts +2 -2
  6. package/dist/types/lib/footnotes.d.ts +4 -2
  7. package/dist/types/lib/utils.d.ts +5 -4
  8. package/dist/types/versions.d.ts +1 -1
  9. package/package.json +37 -36
  10. package/{dist/es/lib/statistics.js → src/__mocks__/styleMock.ts} +2 -14
  11. package/src/assets.ts +20 -0
  12. package/src/classes/collabProvider.ts +38 -0
  13. package/src/clipboard.ts +54 -0
  14. package/src/commands.ts +2109 -0
  15. package/src/components/ChangeHandlingForm.tsx +54 -0
  16. package/src/components/LanguageDropdown/index.tsx +343 -0
  17. package/src/components/affiliations/AffiliationForm.tsx +238 -0
  18. package/src/components/affiliations/AffiliationItem.tsx +151 -0
  19. package/src/components/affiliations/AffiliationList.tsx +71 -0
  20. package/src/components/affiliations/AffiliationsModal.tsx +676 -0
  21. package/src/components/affiliations/AffiliationsPanel.tsx +76 -0
  22. package/src/components/affiliations/CreateAffiliationModal.tsx +135 -0
  23. package/src/components/authors/AuthorDetailsForm.tsx +438 -0
  24. package/src/components/authors/AuthorList.tsx +81 -0
  25. package/src/components/authors/AuthorsModal.tsx +642 -0
  26. package/src/components/authors/AuthorsPanel.tsx +69 -0
  27. package/src/components/authors/CreateAuthorModal.tsx +172 -0
  28. package/src/components/authors/CreditDrawer.tsx +71 -0
  29. package/src/components/authors/DraggableAuthor.tsx +228 -0
  30. package/src/components/authors/useManageAffiliations.tsx +77 -0
  31. package/src/components/authors/useManageCredit.tsx +63 -0
  32. package/src/components/authors-affiliations/AuthorsAndAffiliationsModals.tsx +170 -0
  33. package/src/components/authors-affiliations/GenericPanel.tsx +164 -0
  34. package/src/components/authors-affiliations/ModalTabs.tsx +100 -0
  35. package/src/components/awards/AwardForm.tsx +338 -0
  36. package/src/components/awards/AwardModal.tsx +120 -0
  37. package/src/components/awards/DeleteAwardDiaolog.tsx +52 -0
  38. package/src/components/dialog/ConfirmationDialog.tsx +131 -0
  39. package/src/components/form/CreateModalStyles.tsx +37 -0
  40. package/src/components/form/FormFooter.tsx +54 -0
  41. package/src/components/form/FormPlaceholder.tsx +71 -0
  42. package/src/components/form/ModalFormActions.tsx +88 -0
  43. package/src/components/form/UnsavedLabel.tsx +49 -0
  44. package/src/components/hooks/use-debounce.ts +56 -0
  45. package/src/components/hooks/useAffiliationShowsErrorIndicator.ts +51 -0
  46. package/src/components/hooks/useAuthorShowsErrorIndicator.ts +73 -0
  47. package/src/components/keyboard-shortcuts-modal/FormattedShortcut.tsx +56 -0
  48. package/src/components/keyboard-shortcuts-modal/KeyboardShortcutsModal.tsx +283 -0
  49. package/src/components/keyboard-shortcuts-modal/keyboard-shortcuts.ts +304 -0
  50. package/src/components/keywords/AddKeywordInline.tsx +284 -0
  51. package/src/components/keywords/DeleteKeywordDialog.tsx +52 -0
  52. package/src/components/modal-drawer/GenericDrawer.tsx +65 -0
  53. package/src/components/modal-drawer/GenericDrawerGroup.tsx +125 -0
  54. package/src/components/outline/DraggableTree.tsx +438 -0
  55. package/src/components/outline/ManuscriptOutline.tsx +127 -0
  56. package/src/components/outline/Outline.tsx +141 -0
  57. package/src/components/references/BibliographyItemSource.ts +80 -0
  58. package/src/components/references/CitationEditor.tsx +301 -0
  59. package/src/components/references/CitationViewer.tsx +62 -0
  60. package/src/components/references/ImportBibliographyForm.tsx +232 -0
  61. package/src/components/references/ImportBibliographyModal.tsx +159 -0
  62. package/src/components/references/ReferenceForm/PersonDropDown.tsx +93 -0
  63. package/src/components/references/ReferenceForm/ReferenceForm.tsx +701 -0
  64. package/src/components/references/ReferenceForm/config.ts +133 -0
  65. package/src/components/references/ReferenceForm/styled-components.ts +156 -0
  66. package/src/components/references/ReferenceLine.tsx +43 -0
  67. package/src/components/references/ReferenceSearch.tsx +163 -0
  68. package/src/components/references/ReferenceSearchResults.tsx +113 -0
  69. package/src/components/references/ReferenceSearchResultsPlaceholder.tsx +71 -0
  70. package/src/components/references/ReferenceSearchSection.tsx +124 -0
  71. package/src/components/references/ReferencesEditor.tsx +61 -0
  72. package/src/components/references/ReferencesModal.tsx +352 -0
  73. package/src/components/references/SearchInput.tsx +98 -0
  74. package/src/components/toolbar/InsertEmbedDialog.tsx +222 -0
  75. package/src/components/toolbar/InsertTableDialog.tsx +208 -0
  76. package/src/components/toolbar/ListMenuItem.tsx +203 -0
  77. package/src/components/toolbar/helpers.ts +547 -0
  78. package/src/components/toolbar/type-selector/OptionComponent.tsx +89 -0
  79. package/src/components/toolbar/type-selector/TypeSelector.tsx +157 -0
  80. package/src/components/toolbar/type-selector/styles.ts +79 -0
  81. package/src/components/views/CrossReferenceItems.tsx +199 -0
  82. package/src/components/views/DeleteEmbedDialog.tsx +83 -0
  83. package/src/components/views/DeleteFootnoteDialog.tsx +54 -0
  84. package/src/components/views/FigureDropdown.tsx +423 -0
  85. package/src/components/views/FootnotesSelector.tsx +255 -0
  86. package/src/components/views/InsertSpecialCharacter.tsx +245 -0
  87. package/src/components/views/LinkForm.tsx +220 -0
  88. package/src/components/views/TableCellContextMenu.tsx +241 -0
  89. package/src/configs/ManuscriptsEditor.ts +140 -0
  90. package/src/configs/editor-plugins.ts +119 -0
  91. package/src/configs/editor-views.ts +139 -0
  92. package/src/icons.ts +62 -0
  93. package/src/index.ts +65 -0
  94. package/src/keys/highlight.ts +65 -0
  95. package/src/keys/index.ts +33 -0
  96. package/src/keys/keyword.ts +69 -0
  97. package/src/keys/list.ts +156 -0
  98. package/src/keys/misc.ts +112 -0
  99. package/src/keys/title.ts +221 -0
  100. package/src/lib/__tests__/__fixtures__/doc.json +388 -0
  101. package/src/lib/__tests__/__snapshots__/paste.test.ts.snap +24 -0
  102. package/src/lib/__tests__/authors.test.ts +202 -0
  103. package/src/lib/__tests__/helpers.test.ts +46 -0
  104. package/src/lib/__tests__/paste.test.ts +57 -0
  105. package/src/lib/__tests__/plugins.test.ts +176 -0
  106. package/src/lib/__tests__/url.test.ts +31 -0
  107. package/src/lib/array-reducer.ts +68 -0
  108. package/src/lib/authors-and-affiliations.ts +81 -0
  109. package/src/lib/authors.ts +67 -0
  110. package/src/lib/capabilities.ts +55 -0
  111. package/src/lib/codemirror.ts +37 -0
  112. package/src/lib/comments.ts +123 -0
  113. package/src/lib/context-menu.ts +745 -0
  114. package/src/lib/copy.ts +30 -0
  115. package/src/lib/crossref.ts +90 -0
  116. package/src/lib/dnd.ts +29 -0
  117. package/src/lib/doc.ts +167 -0
  118. package/src/lib/dompurify.ts +28 -0
  119. package/src/lib/files.ts +180 -0
  120. package/src/lib/footnotes.ts +83 -0
  121. package/src/lib/get-media-type.ts +105 -0
  122. package/src/lib/helpers.ts +199 -0
  123. package/src/lib/hierarchy.ts +117 -0
  124. package/src/lib/languages.ts +37 -0
  125. package/src/lib/lists.ts +56 -0
  126. package/src/lib/math.ts +111 -0
  127. package/src/lib/media.ts +334 -0
  128. package/src/lib/navigation-utils.ts +235 -0
  129. package/src/lib/normalize.ts +70 -0
  130. package/src/lib/paste.ts +304 -0
  131. package/src/lib/placeholder.ts +32 -0
  132. package/src/lib/platform.ts +18 -0
  133. package/src/lib/plugins.ts +22 -0
  134. package/src/lib/popper.ts +180 -0
  135. package/src/lib/position-menu.ts +184 -0
  136. package/src/lib/references.ts +94 -0
  137. package/src/lib/template.ts +29 -0
  138. package/src/lib/track-changes-utils.ts +34 -0
  139. package/{dist/types/lib/statistics.d.ts → src/lib/url.ts} +11 -8
  140. package/src/lib/use-do-with-debounce.ts +39 -0
  141. package/src/lib/utils.ts +323 -0
  142. package/src/lib/view.ts +100 -0
  143. package/src/menus.tsx +684 -0
  144. package/src/node-type-icons.tsx +83 -0
  145. package/src/plugins/__tests__/__fixtures__/deleted-footnote.json +140 -0
  146. package/src/plugins/__tests__/__fixtures__/inserted-footnote.json +153 -0
  147. package/src/plugins/__tests__/footnotes.test.ts +67 -0
  148. package/src/plugins/accessibility_element.ts +219 -0
  149. package/src/plugins/add-subtitle.ts +102 -0
  150. package/src/plugins/affiliations.ts +136 -0
  151. package/src/plugins/alt-titles.ts +219 -0
  152. package/src/plugins/bibliography.ts +235 -0
  153. package/src/plugins/comments.ts +328 -0
  154. package/src/plugins/cross-references.ts +70 -0
  155. package/src/plugins/detect-inconsistency/detect-inconsistency-utils.ts +102 -0
  156. package/src/plugins/detect-inconsistency/index.ts +55 -0
  157. package/src/plugins/detect-inconsistency/validators.ts +283 -0
  158. package/src/plugins/doi.ts +66 -0
  159. package/src/plugins/editor-props.ts +39 -0
  160. package/src/plugins/elements.ts +60 -0
  161. package/src/plugins/footnotes.ts +298 -0
  162. package/src/plugins/link.ts +53 -0
  163. package/src/plugins/lock-body.ts +136 -0
  164. package/src/plugins/move-node.ts +55 -0
  165. package/src/plugins/objects.ts +125 -0
  166. package/src/plugins/paragraphs.ts +90 -0
  167. package/src/plugins/persist.ts +64 -0
  168. package/src/plugins/persistent-cursor.ts +66 -0
  169. package/src/plugins/placeholder.ts +219 -0
  170. package/src/plugins/prevent-empty.ts +50 -0
  171. package/src/plugins/search-replace/index.ts +157 -0
  172. package/src/plugins/search-replace/lib.ts +95 -0
  173. package/src/plugins/section_category.ts +212 -0
  174. package/src/plugins/section_title/autocompletion.ts +87 -0
  175. package/src/plugins/section_title/index.ts +105 -0
  176. package/src/plugins/selected-suggestion.ts +243 -0
  177. package/src/plugins/tables-cursor-fix.ts +143 -0
  178. package/src/plugins/translations.ts +263 -0
  179. package/src/rules.ts +60 -0
  180. package/src/selection.ts +112 -0
  181. package/src/testing/default-capabilities.ts +48 -0
  182. package/src/testing/default-editor-data.ts +73 -0
  183. package/src/testing/empty-editor-doc.json +62 -0
  184. package/src/testing/polyfill-dom.ts +43 -0
  185. package/src/testing/section-categories.json +161 -0
  186. package/src/testing/setup-editor.ts +55 -0
  187. package/src/tests.ts +42 -0
  188. package/src/toolbar.tsx +259 -0
  189. package/src/types/@citation-js/core.d.ts +16 -0
  190. package/src/types/@citation-js/index.d.ts +16 -0
  191. package/src/types/@citation-js/plugin-bibtex.d.ts +16 -0
  192. package/src/types/@citation-js/plugin-csl.d.ts +16 -0
  193. package/src/types/@citation-js/plugin-doi.d.ts +16 -0
  194. package/src/types/@citation-js/plugin-enw.d.ts +16 -0
  195. package/src/types/@citation-js/plugin-pubmed.d.ts +16 -0
  196. package/src/types/@citation-js/plugin-ris.d.ts +16 -0
  197. package/src/types/citeproc.d.ts +124 -0
  198. package/src/types/css.d.ts +16 -0
  199. package/src/types/json.d.ts +17 -0
  200. package/src/types/prosemirror-dev-tools.d.ts +16 -0
  201. package/src/types/prosemirror-dropcursor.d.ts +16 -0
  202. package/src/types/styled-components.d.ts +23 -0
  203. package/src/types.ts +49 -0
  204. package/src/useEditor.ts +244 -0
  205. package/src/versions.ts +3 -0
  206. package/src/views/ReactSubView.tsx +145 -0
  207. package/src/views/abstracts.ts +46 -0
  208. package/src/views/accessibility_element.ts +86 -0
  209. package/src/views/affiliations.ts +254 -0
  210. package/src/views/alt_title.ts +85 -0
  211. package/src/views/alt_titles_section.ts +97 -0
  212. package/src/views/attachment.ts +160 -0
  213. package/src/views/attachments.ts +72 -0
  214. package/src/views/author_notes.ts +96 -0
  215. package/src/views/award.ts +194 -0
  216. package/src/views/awards.ts +59 -0
  217. package/src/views/base_node_view.ts +85 -0
  218. package/src/views/bibliography_element.ts +313 -0
  219. package/src/views/block_view.ts +100 -0
  220. package/src/views/blockquote_element.ts +26 -0
  221. package/src/views/blockquote_element_editable.ts +24 -0
  222. package/src/views/box_element.ts +33 -0
  223. package/src/views/caption.ts +37 -0
  224. package/src/views/caption_title.ts +33 -0
  225. package/src/views/citation.ts +67 -0
  226. package/src/views/citation_editable.ts +312 -0
  227. package/src/views/contributors.ts +341 -0
  228. package/src/views/creators.ts +82 -0
  229. package/src/views/cross_reference.ts +74 -0
  230. package/src/views/cross_reference_editable.ts +113 -0
  231. package/src/views/editable_block.ts +141 -0
  232. package/src/views/embed.ts +345 -0
  233. package/src/views/empty.ts +26 -0
  234. package/src/views/equation.ts +47 -0
  235. package/src/views/equation_editable.ts +84 -0
  236. package/src/views/equation_element.ts +29 -0
  237. package/src/views/equation_element_editable.ts +21 -0
  238. package/src/views/figure.ts +84 -0
  239. package/src/views/figure_editable.ts +361 -0
  240. package/src/views/figure_element.ts +197 -0
  241. package/src/views/figure_element_editable.ts +21 -0
  242. package/src/views/footnote.ts +236 -0
  243. package/src/views/footnotes_element.ts +54 -0
  244. package/src/views/general_table_footnote.ts +140 -0
  245. package/src/views/hero_image.ts +76 -0
  246. package/src/views/hero_image_editable.ts +21 -0
  247. package/src/views/image_element.ts +373 -0
  248. package/src/views/image_element_editable.ts +21 -0
  249. package/src/views/inline_equation.ts +47 -0
  250. package/src/views/inline_equation_editable.ts +70 -0
  251. package/src/views/inline_footnote.ts +264 -0
  252. package/src/views/inline_footnote_editable.ts +20 -0
  253. package/src/views/keyword.ts +127 -0
  254. package/src/views/keyword_group.ts +109 -0
  255. package/src/views/link.ts +27 -0
  256. package/src/views/link_editable.ts +169 -0
  257. package/src/views/list.ts +46 -0
  258. package/src/views/list_item.ts +26 -0
  259. package/src/views/paragraph.ts +26 -0
  260. package/src/views/paragraph_editable.ts +21 -0
  261. package/src/views/placeholder.ts +35 -0
  262. package/src/views/placeholder_element.ts +38 -0
  263. package/src/views/placeholder_element_editable.ts +21 -0
  264. package/src/views/pullquote_element.ts +106 -0
  265. package/src/views/pullquote_element_editable.ts +24 -0
  266. package/src/views/quote_image_editable.ts +84 -0
  267. package/src/views/section.ts +64 -0
  268. package/src/views/section_label.ts +20 -0
  269. package/src/views/section_title.ts +87 -0
  270. package/src/views/section_title_editable.ts +21 -0
  271. package/src/views/subtitle.ts +42 -0
  272. package/src/views/subtitle_editable.ts +20 -0
  273. package/src/views/subtitles.ts +34 -0
  274. package/src/views/subtitles_editable.ts +21 -0
  275. package/src/views/supplement.ts +236 -0
  276. package/src/views/supplement_editable.ts +20 -0
  277. package/src/views/supplements.ts +65 -0
  278. package/src/views/supplements_editable.ts +21 -0
  279. package/src/views/table_cell.ts +150 -0
  280. package/src/views/table_element.ts +33 -0
  281. package/src/views/table_element_editable.ts +21 -0
  282. package/src/views/table_element_footer.ts +41 -0
  283. package/src/views/title.ts +46 -0
  284. package/src/views/title_editable.ts +20 -0
  285. package/src/views/trans_graphical_abstract.ts +55 -0
  286. package/src/views/trans_graphical_abstract_editable.ts +21 -0
  287. package/src/views/translated_abstract.ts +53 -0
  288. package/src/views/translated_abstract_editable.ts +21 -0
  289. package/dist/cjs/lib/statistics.js +0 -38
@@ -0,0 +1,30 @@
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 { Slice } from 'prosemirror-model'
17
+
18
+ // TODO: checking the ability to remove the following logic, after the following ticket LEAN-4118 is resolved
19
+ export const transformCopied = (slice: Slice) => {
20
+ if (
21
+ slice.openStart !== slice.openEnd &&
22
+ (slice.content.firstChild?.type.isBlock ||
23
+ slice.content.lastChild?.type.isBlock)
24
+ ) {
25
+ const cutDepth = Math.min(slice.openStart, slice.openEnd)
26
+ // rebalance slice sides to be digestible for track changes plugin
27
+ return new Slice(slice.content, cutDepth, cutDepth)
28
+ }
29
+ return slice
30
+ }
@@ -0,0 +1,90 @@
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 { generateNodeID, schema } from '@manuscripts/transform'
18
+
19
+ import {
20
+ BibliographyItemSearch,
21
+ BibliographyItemSource,
22
+ } from '../components/references/BibliographyItemSource'
23
+
24
+ type CrossrefItem = {
25
+ [key: string]: unknown
26
+ }
27
+
28
+ type CrossrefResponse = {
29
+ message: {
30
+ items: CrossrefItem[]
31
+ 'total-results': number
32
+ }
33
+ }
34
+
35
+ const search = (query: string, limit: number): BibliographyItemSearch => {
36
+ const controller = new AbortController()
37
+ const params = new URLSearchParams({
38
+ filter: 'type:journal-article',
39
+ query,
40
+ rows: String(limit),
41
+ })
42
+
43
+ const promise = searchAsync(params, controller)
44
+
45
+ return new BibliographyItemSearch((resolve, reject) => {
46
+ promise.then(resolve).catch(reject)
47
+ }, controller)
48
+ }
49
+
50
+ const searchAsync = async (
51
+ params: URLSearchParams,
52
+ controller: AbortController
53
+ ) => {
54
+ const response = await fetch(`https://api.crossref.org/works?${params}`, {
55
+ signal: controller.signal,
56
+ })
57
+
58
+ if (!response.ok) {
59
+ throw new Error('There was a problem searching for this query.')
60
+ }
61
+ const data = (await response.json()) as CrossrefResponse
62
+ const items = data.message.items.map(fixItem)
63
+ const total = data.message['total-results']
64
+
65
+ return {
66
+ items,
67
+ total,
68
+ }
69
+ }
70
+
71
+ export const Crossref: BibliographyItemSource = {
72
+ id: 'crossref',
73
+ label: 'External sources',
74
+ search,
75
+ }
76
+
77
+ const fixItem = (item: CrossrefItem): CSL.Data => {
78
+ for (const key in item) {
79
+ if (key === 'author' || key === 'editor') {
80
+ continue
81
+ }
82
+ const value = item[key]
83
+ if (Array.isArray(value)) {
84
+ const [data] = item[key] as string[]
85
+ item[key] = data || undefined
86
+ }
87
+ }
88
+ item.id = generateNodeID(schema.nodes.bibliography_item)
89
+ return item as CSL.Data
90
+ }
package/src/lib/dnd.ts ADDED
@@ -0,0 +1,29 @@
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 { DropTargetMonitor, XYCoord } from 'react-dnd'
17
+
18
+ export type DropSide = 'before' | 'after'
19
+
20
+ export const getDropSide = (element: Element, monitor: DropTargetMonitor) => {
21
+ const rect = element.getBoundingClientRect()
22
+
23
+ // Get vertical middle
24
+ const middle = (rect.bottom - rect.top) / 2
25
+
26
+ const offset = monitor.getClientOffset() as XYCoord
27
+
28
+ return offset.y > middle + rect.top ? 'after' : 'before'
29
+ }
package/src/lib/doc.ts ADDED
@@ -0,0 +1,167 @@
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
+ AwardsNode,
18
+ generateNodeID,
19
+ ManuscriptNode,
20
+ ManuscriptTransaction,
21
+ schema,
22
+ SupplementNode,
23
+ SupplementsNode,
24
+ } from '@manuscripts/transform'
25
+ import { findChildren, findChildrenByType } from 'prosemirror-utils'
26
+
27
+ import { findInsertionPosition } from './utils'
28
+
29
+ export const insertAwardsNode = (tr: ManuscriptTransaction) => {
30
+ const doc = tr.doc
31
+ const awards = findChildrenByType(doc, schema.nodes.awards)[0]
32
+ if (awards) {
33
+ return awards
34
+ }
35
+ const pos = findInsertionPosition(schema.nodes.awards, doc)
36
+ // const node = schema.nodes.awards.create() as AwardsNode
37
+ const node = schema.nodes.awards.createAndFill() as AwardsNode
38
+ tr.insert(pos, node)
39
+ return {
40
+ node,
41
+ pos,
42
+ }
43
+ }
44
+
45
+ export const upsertSupplementsSection = (
46
+ tr: ManuscriptTransaction,
47
+ supplement: SupplementNode
48
+ ) => {
49
+ const doc = tr.doc
50
+ const supplements = findChildrenByType(doc, schema.nodes.supplements)[0]
51
+ if (supplements) {
52
+ // Section exists -> insert inside it
53
+ const pos = supplements.pos + supplements.node.nodeSize - 1
54
+ tr.insert(pos, supplement)
55
+ return { node: supplements.node, pos }
56
+ }
57
+
58
+ // Section missing -> create new with supplement inside
59
+ const pos = findInsertionPosition(schema.nodes.supplements, doc)
60
+ const node = schema.nodes.supplements.createAndFill(
61
+ { id: generateNodeID(schema.nodes.supplements) },
62
+ [
63
+ schema.nodes.section_title.create(undefined, schema.text('Supplements')),
64
+ supplement,
65
+ ]
66
+ ) as SupplementsNode
67
+
68
+ tr.insert(pos, node)
69
+ return {
70
+ node,
71
+ pos,
72
+ }
73
+ }
74
+
75
+ export const insertAttachmentsNode = (tr: ManuscriptTransaction) => {
76
+ const attachmentsNodes = findChildrenByType(tr.doc, schema.nodes.attachments)
77
+ if (attachmentsNodes.length) {
78
+ return {
79
+ node: attachmentsNodes[0].node,
80
+ pos: attachmentsNodes[0].pos,
81
+ }
82
+ }
83
+ const pos = findInsertionPosition(schema.nodes.attachments, tr.doc)
84
+ const node = schema.nodes.attachments.create({
85
+ id: generateNodeID(schema.nodes.attachments),
86
+ })
87
+ tr.insert(pos, node)
88
+ return { node, pos }
89
+ }
90
+
91
+ export const insertFootnotesSection = (tr: ManuscriptTransaction) => {
92
+ const doc = tr.doc
93
+ const section = findChildrenByType(doc, schema.nodes.footnotes_section)[0]
94
+ if (section) {
95
+ return section
96
+ }
97
+
98
+ const backmatter = findChildrenByType(doc, schema.nodes.backmatter, true)
99
+
100
+ const backmatterNode = backmatter[0].node
101
+ const backmatterPos = backmatter[0].pos
102
+
103
+ // Find the last child node in the backmatter (references section)
104
+ const lastChild =
105
+ backmatterNode.content.childCount > 0
106
+ ? backmatterNode.content.child(backmatterNode.content.childCount - 1)
107
+ : null
108
+
109
+ const insertPos =
110
+ lastChild && lastChild.type === schema.nodes.bibliography_section
111
+ ? backmatterPos + backmatterNode.content.size - lastChild.nodeSize // Insert before last child (refernces section)
112
+ : backmatterPos + backmatterNode.content.size // Insert at the end of backmatter
113
+
114
+ const pos = tr.mapping.map(insertPos)
115
+
116
+ const node = schema.nodes.footnotes_section.create({}, [
117
+ schema.nodes.section_title.create({}, schema.text('Footnotes')),
118
+ ])
119
+ tr.insert(pos, node)
120
+ return {
121
+ node,
122
+ pos,
123
+ }
124
+ }
125
+
126
+ export const findAbstractsNode = (doc: ManuscriptNode) => {
127
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
128
+ return findChildrenByType(doc, schema.nodes.abstracts)[0]!
129
+ }
130
+
131
+ export const findBody = (doc: ManuscriptNode) => {
132
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
133
+ return findChildrenByType(doc, schema.nodes.body)[0]!
134
+ }
135
+
136
+ export const findBackmatter = (doc: ManuscriptNode) => {
137
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
138
+ return findChildrenByType(doc, schema.nodes.backmatter)[0]!
139
+ }
140
+
141
+ export const findBibliographySection = (doc: ManuscriptNode) => {
142
+ return findChildrenByType(doc, schema.nodes.bibliography_section)[0]
143
+ }
144
+
145
+ export const findFootnotesSection = (doc: ManuscriptNode) => {
146
+ return findChildrenByType(doc, schema.nodes.footnotes_section)[0]
147
+ }
148
+
149
+ export const findGraphicalAbstractFigureElement = (doc: ManuscriptNode) => {
150
+ const ga = findChildrenByType(doc, schema.nodes.graphical_abstract_section)[0]
151
+ if (!ga) {
152
+ return
153
+ }
154
+ const element = findChildrenByType(ga.node, schema.nodes.figure_element)[0]
155
+ if (!element) {
156
+ return
157
+ }
158
+ return {
159
+ node: element.node,
160
+ pos: ga.pos + element.pos + 1,
161
+ }
162
+ }
163
+
164
+ export const findNodeByID = (doc: ManuscriptNode, id: string) => {
165
+ const children = findChildren(doc, (n) => n.attrs.id === id)
166
+ return children[0]
167
+ }
@@ -0,0 +1,28 @@
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 purify, { Config } from 'dompurify'
18
+
19
+ type Sanitize = (
20
+ dirty: string,
21
+ config?: Pick<Config, 'USE_PROFILES' | 'ALLOWED_TAGS'>
22
+ ) => DocumentFragment
23
+
24
+ export const sanitize: Sanitize = (dirty, config) =>
25
+ purify.sanitize(dirty, {
26
+ RETURN_DOM_FRAGMENT: true,
27
+ ...config,
28
+ })
@@ -0,0 +1,180 @@
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 { ManuscriptNode, schema } from '@manuscripts/transform'
17
+ import { findChildrenByType } from 'prosemirror-utils'
18
+
19
+ import { isHidden } from './track-changes-utils'
20
+
21
+ export type FileAttachment = {
22
+ id: string
23
+ name: string
24
+ link?: string
25
+ createdDate?: Date
26
+ }
27
+
28
+ export type NodeFile = {
29
+ node: ManuscriptNode
30
+ pos: number
31
+ file: FileAttachment
32
+ }
33
+
34
+ export type ElementFiles = {
35
+ node: ManuscriptNode
36
+ pos: number
37
+ files: NodeFile[]
38
+ }
39
+
40
+ export type ManuscriptFiles = {
41
+ figures: ElementFiles[]
42
+ supplements: NodeFile[]
43
+ attachments: NodeFile[]
44
+ linkedFiles: NodeFile[]
45
+ others: FileAttachment[]
46
+ }
47
+
48
+ const MISSING_FILE: FileAttachment = {
49
+ id: '',
50
+ name: '',
51
+ }
52
+
53
+ export type Upload = (
54
+ file: File,
55
+ OnProgress?: (percentage: number) => void
56
+ ) => Promise<FileAttachment>
57
+
58
+ export type Download = (file: FileAttachment) => void
59
+
60
+ export type PreviewLink = (file: FileAttachment) => string | undefined
61
+
62
+ export type FileManagement = {
63
+ upload: Upload
64
+ download: Download
65
+ previewLink: PreviewLink
66
+ }
67
+
68
+ const figureTypes = [
69
+ schema.nodes.figure_element,
70
+ schema.nodes.image_element,
71
+ schema.nodes.hero_image,
72
+ schema.nodes.embed,
73
+ ]
74
+
75
+ export function memoGroupFiles() {
76
+ let prevFiles: FileAttachment[] = []
77
+ let prevDoc: ManuscriptNode | undefined = undefined
78
+ let result: ManuscriptFiles | undefined
79
+
80
+ return function (doc: ManuscriptNode, files: FileAttachment[]) {
81
+ if (result && prevDoc === doc && prevFiles === files) {
82
+ return result
83
+ }
84
+ prevDoc = doc
85
+ prevFiles = files
86
+ return groupFiles(doc, files)
87
+ }
88
+ }
89
+
90
+ export const groupFiles = (
91
+ doc: ManuscriptNode,
92
+ files: FileAttachment[]
93
+ ): ManuscriptFiles => {
94
+ const fileMap = new Map(files.map((f) => [f.id, f]))
95
+ const figures: ElementFiles[] = []
96
+ const supplements: NodeFile[] = []
97
+ const linkedFiles: NodeFile[] = []
98
+ const attachments: NodeFile[] = []
99
+
100
+ const getFile = (href: string) => {
101
+ const file = fileMap.get(href)
102
+ if (file) {
103
+ fileMap.delete(href)
104
+ return file
105
+ } else {
106
+ return MISSING_FILE
107
+ }
108
+ }
109
+
110
+ const getFigureElementFiles = (node: ManuscriptNode, pos: number) => {
111
+ const figureFiles = []
112
+
113
+ if (node.type === schema.nodes.embed) {
114
+ if (node.attrs.href) {
115
+ figureFiles.push({
116
+ node,
117
+ pos,
118
+ file: getFile(node.attrs.href),
119
+ })
120
+ }
121
+ } else {
122
+ for (const figure of findChildrenByType(node, schema.nodes.figure)) {
123
+ if (isHidden(figure.node)) {
124
+ continue
125
+ }
126
+ figureFiles.push({
127
+ node: figure.node,
128
+ pos: pos + figure.pos + 1,
129
+ file: getFile(figure.node.attrs.src),
130
+ })
131
+ }
132
+ }
133
+
134
+ return {
135
+ node,
136
+ pos,
137
+ files: figureFiles,
138
+ }
139
+ }
140
+
141
+ doc.descendants((node, pos) => {
142
+ if (isHidden(node)) {
143
+ return
144
+ }
145
+ if (figureTypes.includes(node.type)) {
146
+ figures.push(getFigureElementFiles(node, pos))
147
+ }
148
+ if (node.type === schema.nodes.image_element) {
149
+ if (node.attrs.extLink) {
150
+ linkedFiles.push({
151
+ node,
152
+ pos,
153
+ file: getFile(node.attrs.extLink),
154
+ })
155
+ }
156
+ }
157
+ if (node.type === schema.nodes.supplement) {
158
+ supplements.push({
159
+ node,
160
+ pos,
161
+ file: getFile(node.attrs.href),
162
+ })
163
+ }
164
+ if (node.type === schema.nodes.attachment) {
165
+ attachments.push({
166
+ node,
167
+ pos,
168
+ file: getFile(node.attrs.href),
169
+ })
170
+ }
171
+ })
172
+
173
+ return {
174
+ figures,
175
+ supplements,
176
+ attachments,
177
+ linkedFiles,
178
+ others: [...fileMap.values()],
179
+ }
180
+ }
@@ -0,0 +1,83 @@
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 {
18
+ FootnoteNode,
19
+ generateNodeID,
20
+ ManuscriptEditorState,
21
+ ManuscriptNode,
22
+ schema,
23
+ } from '@manuscripts/transform'
24
+ import { Selection } from 'prosemirror-state'
25
+ import {
26
+ ContentNodeWithPos,
27
+ findParentNodeOfType,
28
+ findParentNodeOfTypeClosestToPos,
29
+ } from 'prosemirror-utils'
30
+
31
+ import { footnotesKey } from '../plugins/footnotes'
32
+
33
+ export const findFootnotesContainerNode = (
34
+ doc: ManuscriptNode,
35
+ pos: number
36
+ ) => {
37
+ const $pos = doc.resolve(pos)
38
+ return (
39
+ findParentNodeOfTypeClosestToPos($pos, schema.nodes.table_element) || {
40
+ node: doc,
41
+ pos: 0,
42
+ }
43
+ )
44
+ }
45
+
46
+ export const findParentFootnote: (selection: Selection) => ContentNodeWithPos | undefined = findParentNodeOfType([
47
+ schema.nodes.footnote,
48
+ schema.nodes.general_table_footnote,
49
+ ])
50
+
51
+ export const getFootnotesElementState = (
52
+ state: ManuscriptEditorState,
53
+ id: string
54
+ ) => {
55
+ const fns = footnotesKey.getState(state)
56
+ if (!fns) {
57
+ return
58
+ }
59
+ const elementID = fns.footnotesElementIDs.get(id)
60
+ if (!elementID) {
61
+ return
62
+ }
63
+ return fns.footnotesElements.get(elementID)
64
+ }
65
+
66
+ export const getFootnoteLabel = (
67
+ state: ManuscriptEditorState,
68
+ footnote: FootnoteNode
69
+ ) => {
70
+ const id = footnote.attrs.id
71
+ const fns = getFootnotesElementState(state, id)
72
+ return fns?.labels.get(id) || ''
73
+ }
74
+
75
+ export const createFootnote = () => {
76
+ return schema.nodes.footnote.createAndFill(
77
+ {
78
+ id: generateNodeID(schema.nodes.footnote),
79
+ kind: 'footnote',
80
+ },
81
+ [schema.nodes.paragraph.create({})]
82
+ ) as FootnoteNode
83
+ }