@manuscripts/body-editor 3.12.67 → 3.13.1
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,373 @@
|
|
|
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
|
+
import { ContextMenu } from '@manuscripts/style-guide'
|
|
18
|
+
import { FigureNode, ImageElementNode, schema } from '@manuscripts/transform'
|
|
19
|
+
|
|
20
|
+
import { deleteIcon, linkIcon } from '../icons'
|
|
21
|
+
import {
|
|
22
|
+
addInteractionHandlers,
|
|
23
|
+
createMediaPlaceholder,
|
|
24
|
+
MediaType,
|
|
25
|
+
} from '../lib/media'
|
|
26
|
+
import { handleEnterKey } from '../lib/navigation-utils'
|
|
27
|
+
import { createPositionMenuWrapper } from '../lib/position-menu'
|
|
28
|
+
import { Trackable } from '../types'
|
|
29
|
+
import BlockView from './block_view'
|
|
30
|
+
import { createNodeView } from './creators'
|
|
31
|
+
import ReactSubView from './ReactSubView'
|
|
32
|
+
|
|
33
|
+
export enum figurePositions {
|
|
34
|
+
left = 'half-left',
|
|
35
|
+
right = 'half-right',
|
|
36
|
+
default = '',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class ImageElementView extends BlockView<Trackable<ImageElementNode>> {
|
|
40
|
+
public container: HTMLElement
|
|
41
|
+
public subcontainer: HTMLElement
|
|
42
|
+
public extLinkEditorContainer: HTMLDivElement
|
|
43
|
+
private positionMenuWrapper: HTMLDivElement
|
|
44
|
+
private figurePosition: string
|
|
45
|
+
private isEditingExtLink = false
|
|
46
|
+
|
|
47
|
+
public ignoreMutation = () => true
|
|
48
|
+
|
|
49
|
+
upload = async (file: File) => {
|
|
50
|
+
const result = await this.props.fileManagement.upload(file)
|
|
51
|
+
if (!result) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
this.setIsEditingExtLink(false)
|
|
55
|
+
this.setExtLink({ extLink: result.id })
|
|
56
|
+
this.updateContents()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public initialise() {
|
|
60
|
+
super.initialise()
|
|
61
|
+
this.upload = this.upload.bind(this)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public createDOM() {
|
|
65
|
+
super.createDOM()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public createElement() {
|
|
69
|
+
this.container = document.createElement('div')
|
|
70
|
+
this.container.classList.add('block')
|
|
71
|
+
this.dom.appendChild(this.container)
|
|
72
|
+
|
|
73
|
+
// figure group
|
|
74
|
+
this.subcontainer = document.createElement('div')
|
|
75
|
+
this.subcontainer.classList.add('figure-block-group')
|
|
76
|
+
|
|
77
|
+
this.contentDOM = document.createElement('div')
|
|
78
|
+
this.contentDOM.setAttribute('id', this.node.attrs.id)
|
|
79
|
+
this.contentDOM.classList.add('figure-block')
|
|
80
|
+
|
|
81
|
+
this.subcontainer.appendChild(this.contentDOM)
|
|
82
|
+
this.container.appendChild(this.subcontainer)
|
|
83
|
+
this.addTools()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public updateContents() {
|
|
87
|
+
super.updateContents()
|
|
88
|
+
this.addTools()
|
|
89
|
+
this.addExternalLinkedFileEditor()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
protected addTools() {
|
|
93
|
+
this.addPositionMenu()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected addPositionMenu() {
|
|
97
|
+
if (this.props.getCapabilities()?.editArticle) {
|
|
98
|
+
// Remove existing position menu if it exists
|
|
99
|
+
const existingMenu = this.container.querySelector('.position-menu')
|
|
100
|
+
if (existingMenu) {
|
|
101
|
+
existingMenu.remove()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const firstFigure = this.getFirstFigure()
|
|
105
|
+
this.figurePosition = firstFigure?.attrs.type || figurePositions.default
|
|
106
|
+
|
|
107
|
+
this.positionMenuWrapper = createPositionMenuWrapper(
|
|
108
|
+
this.figurePosition,
|
|
109
|
+
this.showPositionMenu,
|
|
110
|
+
this.props
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
this.container.prepend(this.positionMenuWrapper)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Gets the first figure node from the element.
|
|
119
|
+
* Optimized for image_element (direct access) vs figure_element (loop through all).
|
|
120
|
+
* @returns The first figure node or null if no figure exists
|
|
121
|
+
*/
|
|
122
|
+
private getFirstFigure(): FigureNode | null {
|
|
123
|
+
// Optimize for image_element which only has one figure
|
|
124
|
+
if (this.node.type === schema.nodes.image_element) {
|
|
125
|
+
// Direct access to the single figure in image_element
|
|
126
|
+
const figureNode = this.node.firstChild
|
|
127
|
+
if (figureNode && figureNode.type === schema.nodes.figure) {
|
|
128
|
+
return figureNode as FigureNode
|
|
129
|
+
}
|
|
130
|
+
return null
|
|
131
|
+
} else {
|
|
132
|
+
// For figure_element, find the first figure
|
|
133
|
+
let firstFigure: FigureNode | null = null
|
|
134
|
+
this.node.forEach((node) => {
|
|
135
|
+
if (node.type === schema.nodes.figure && !firstFigure) {
|
|
136
|
+
firstFigure = node as FigureNode
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
return firstFigure
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Gets all figure nodes and their positions from the element.
|
|
145
|
+
* Optimized for image_element (direct access) vs figure_element (loop through all).
|
|
146
|
+
* @returns Array of figure nodes with their positions
|
|
147
|
+
*/
|
|
148
|
+
private getAllFigures() {
|
|
149
|
+
const figures: Array<{ node: FigureNode; pos: number }> = []
|
|
150
|
+
let pos = this.getPos() + 1
|
|
151
|
+
|
|
152
|
+
if (this.node.type === schema.nodes.image_element) {
|
|
153
|
+
const figureNode = this.node.firstChild
|
|
154
|
+
if (figureNode && figureNode.type === schema.nodes.figure) {
|
|
155
|
+
figures.push({ node: figureNode as FigureNode, pos })
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
this.node.forEach((node) => {
|
|
159
|
+
if (node.type === schema.nodes.figure) {
|
|
160
|
+
figures.push({ node: node as FigureNode, pos })
|
|
161
|
+
}
|
|
162
|
+
pos += node.nodeSize
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return figures
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private showPositionMenu = () => {
|
|
170
|
+
const firstFigure = this.getFirstFigure()
|
|
171
|
+
if (!firstFigure) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.props.popper.destroy()
|
|
176
|
+
|
|
177
|
+
const options = [
|
|
178
|
+
{
|
|
179
|
+
label: 'Left',
|
|
180
|
+
action: () => {
|
|
181
|
+
this.props.popper.destroy()
|
|
182
|
+
this.updateAllFiguresPosition(figurePositions.left)
|
|
183
|
+
},
|
|
184
|
+
icon: 'ImageLeft',
|
|
185
|
+
selected: this.figurePosition === figurePositions.left,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
label: 'Default',
|
|
189
|
+
action: () => {
|
|
190
|
+
this.props.popper.destroy()
|
|
191
|
+
this.updateAllFiguresPosition(figurePositions.default)
|
|
192
|
+
},
|
|
193
|
+
icon: 'ImageDefault',
|
|
194
|
+
selected: !this.figurePosition,
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
label: 'Right',
|
|
198
|
+
action: () => {
|
|
199
|
+
this.props.popper.destroy()
|
|
200
|
+
this.updateAllFiguresPosition(figurePositions.right)
|
|
201
|
+
},
|
|
202
|
+
icon: 'ImageRight',
|
|
203
|
+
selected: this.figurePosition === figurePositions.right,
|
|
204
|
+
},
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
const componentProps = {
|
|
208
|
+
actions: options,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.props.popper.show(
|
|
212
|
+
this.positionMenuWrapper,
|
|
213
|
+
ReactSubView(
|
|
214
|
+
this.props,
|
|
215
|
+
ContextMenu,
|
|
216
|
+
componentProps,
|
|
217
|
+
this.node,
|
|
218
|
+
this.getPos,
|
|
219
|
+
this.view,
|
|
220
|
+
['context-menu', 'position-menu']
|
|
221
|
+
),
|
|
222
|
+
'left',
|
|
223
|
+
false
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Updates the position type for all figures within this element.
|
|
229
|
+
* This affects all figures in figure_element, or the single figure in image_element.
|
|
230
|
+
* @param position - The new position type ('half-left', 'half-right', or '')
|
|
231
|
+
*/
|
|
232
|
+
private updateAllFiguresPosition(position: string) {
|
|
233
|
+
const figures = this.getAllFigures()
|
|
234
|
+
const { tr } = this.view.state
|
|
235
|
+
|
|
236
|
+
figures.forEach(({ node, pos }) => {
|
|
237
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
238
|
+
...node.attrs,
|
|
239
|
+
type: position,
|
|
240
|
+
})
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
this.view.dispatch(tr)
|
|
244
|
+
this.figurePosition = position
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// external link editor
|
|
248
|
+
private removeExtLink = () => {
|
|
249
|
+
this.setExtLink({ extLink: '' })
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private setExtLink = (newAttrs: { extLink: string }) => {
|
|
253
|
+
this.setIsEditingExtLink(false)
|
|
254
|
+
const { tr } = this.view.state
|
|
255
|
+
const pos = this.getPos()
|
|
256
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
257
|
+
...this.node.attrs,
|
|
258
|
+
...newAttrs,
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
this.view.dispatch(tr)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private setIsEditingExtLink = (val: boolean) => {
|
|
265
|
+
this.isEditingExtLink = val
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private createDnDPlaceholder() {
|
|
269
|
+
const can = this.props.getCapabilities()
|
|
270
|
+
const label = document.createElement('div')
|
|
271
|
+
label.classList.add('accessibility_element_label')
|
|
272
|
+
label.innerText = 'Link'
|
|
273
|
+
const container = document.createElement('div')
|
|
274
|
+
container.classList.add('ext-link-editor-placeholder-container')
|
|
275
|
+
|
|
276
|
+
const placeholder = createMediaPlaceholder(
|
|
277
|
+
MediaType.ExternalLink,
|
|
278
|
+
this.view,
|
|
279
|
+
this.getPos,
|
|
280
|
+
this.props
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
const closeButton = document.createElement('button')
|
|
284
|
+
closeButton.classList.add('close-button')
|
|
285
|
+
closeButton.setAttribute('aria-label', 'Close')
|
|
286
|
+
const handleClose = () => {
|
|
287
|
+
this.setIsEditingExtLink(false)
|
|
288
|
+
this.updateContents()
|
|
289
|
+
}
|
|
290
|
+
closeButton.addEventListener('click', handleClose)
|
|
291
|
+
closeButton.addEventListener('keydown', handleEnterKey(handleClose))
|
|
292
|
+
|
|
293
|
+
container.append(placeholder, closeButton)
|
|
294
|
+
this.extLinkEditorContainer.append(label, container)
|
|
295
|
+
if (can.uploadFile) {
|
|
296
|
+
addInteractionHandlers(placeholder, this.upload, '*/*')
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private createAddLinkButton() {
|
|
301
|
+
const button = document.createElement('div')
|
|
302
|
+
button.innerHTML = linkIcon
|
|
303
|
+
const buttonText = document.createElement('span')
|
|
304
|
+
buttonText.textContent = 'Add link'
|
|
305
|
+
button.appendChild(buttonText)
|
|
306
|
+
button.setAttribute('aria-label', 'Add linked file')
|
|
307
|
+
button.classList.add('icon-button')
|
|
308
|
+
button.tabIndex = 0
|
|
309
|
+
const handleAdd = () => {
|
|
310
|
+
this.setIsEditingExtLink(true)
|
|
311
|
+
this.updateContents()
|
|
312
|
+
}
|
|
313
|
+
button.addEventListener('click', handleAdd)
|
|
314
|
+
button.addEventListener('keydown', handleEnterKey(handleAdd))
|
|
315
|
+
this.extLinkEditorContainer.appendChild(button)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private createLinkedFile() {
|
|
319
|
+
const extLink = this.node.attrs.extLink
|
|
320
|
+
const files = this.props.getFiles()
|
|
321
|
+
const file = extLink ? files.find((f) => f.id === extLink) : undefined
|
|
322
|
+
|
|
323
|
+
const fileName = file ? `${file.name.trim()}` : 'File does not exist.'
|
|
324
|
+
const div = document.createElement('div')
|
|
325
|
+
div.classList.add('linked-file-info')
|
|
326
|
+
div.innerHTML = `<p>${linkIcon} <span>${fileName}</span></p>`
|
|
327
|
+
|
|
328
|
+
const removeButton = document.createElement('button')
|
|
329
|
+
removeButton.classList.add('icon-button', 'remove-button')
|
|
330
|
+
removeButton.setAttribute('aria-label', 'Remove link')
|
|
331
|
+
removeButton.innerHTML = deleteIcon
|
|
332
|
+
const handleRemove = () => {
|
|
333
|
+
this.isEditingExtLink = false
|
|
334
|
+
this.removeExtLink()
|
|
335
|
+
}
|
|
336
|
+
removeButton.addEventListener('click', handleRemove)
|
|
337
|
+
removeButton.addEventListener('keydown', handleEnterKey(handleRemove))
|
|
338
|
+
|
|
339
|
+
div.appendChild(removeButton)
|
|
340
|
+
this.extLinkEditorContainer.appendChild(div)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private addExternalLinkedFileEditor() {
|
|
344
|
+
if (this.node.type === schema.nodes.image_element) {
|
|
345
|
+
this.extLinkEditorContainer = this.container.querySelector(
|
|
346
|
+
'.ext-link-editor-container'
|
|
347
|
+
) as HTMLDivElement
|
|
348
|
+
if (this.extLinkEditorContainer) {
|
|
349
|
+
this.extLinkEditorContainer.innerHTML = ''
|
|
350
|
+
} else {
|
|
351
|
+
this.extLinkEditorContainer = document.createElement('div')
|
|
352
|
+
this.extLinkEditorContainer.contentEditable = 'false'
|
|
353
|
+
this.extLinkEditorContainer.classList.add('ext-link-editor-container')
|
|
354
|
+
}
|
|
355
|
+
// add link button
|
|
356
|
+
if (!this.isEditingExtLink && !this.node.attrs.extLink) {
|
|
357
|
+
this.createAddLinkButton()
|
|
358
|
+
}
|
|
359
|
+
//dnd placeholder
|
|
360
|
+
if (this.isEditingExtLink && !this.node.attrs.extLink) {
|
|
361
|
+
this.createDnDPlaceholder()
|
|
362
|
+
}
|
|
363
|
+
// linked file exists
|
|
364
|
+
if (this.node.attrs.extLink) {
|
|
365
|
+
this.createLinkedFile()
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
this.subcontainer.appendChild(this.extLinkEditorContainer)
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export default createNodeView(ImageElementView)
|
|
@@ -0,0 +1,21 @@
|
|
|
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 { createEditableNodeView } from './creators'
|
|
18
|
+
import { EditableBlock } from './editable_block'
|
|
19
|
+
import { ImageElementView } from './image_element'
|
|
20
|
+
|
|
21
|
+
export default createEditableNodeView(EditableBlock(ImageElementView))
|
|
@@ -0,0 +1,47 @@
|
|
|
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 { InlineEquationNode, ManuscriptNodeView } from '@manuscripts/transform'
|
|
18
|
+
|
|
19
|
+
import { renderMath } from '../lib/math'
|
|
20
|
+
import { Trackable } from '../types'
|
|
21
|
+
import { BaseNodeView } from './base_node_view'
|
|
22
|
+
import { createNodeView } from './creators'
|
|
23
|
+
|
|
24
|
+
export class InlineEquationView
|
|
25
|
+
extends BaseNodeView<Trackable<InlineEquationNode>>
|
|
26
|
+
implements ManuscriptNodeView
|
|
27
|
+
{
|
|
28
|
+
public initialise() {
|
|
29
|
+
this.createDOM()
|
|
30
|
+
this.updateContents()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public updateContents() {
|
|
34
|
+
super.updateContents()
|
|
35
|
+
this.dom.innerHTML = this.node.attrs.contents
|
|
36
|
+
renderMath(this.dom)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public ignoreMutation = () => true
|
|
40
|
+
|
|
41
|
+
protected createDOM() {
|
|
42
|
+
this.dom = document.createElement('span')
|
|
43
|
+
this.dom.classList.add('equation')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default createNodeView(InlineEquationView)
|
|
@@ -0,0 +1,70 @@
|
|
|
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 { NodeSelection } from 'prosemirror-state'
|
|
18
|
+
|
|
19
|
+
import { createEditableNodeView } from './creators'
|
|
20
|
+
import { InlineEquationView } from './inline_equation'
|
|
21
|
+
|
|
22
|
+
export class InlineEquationEditableView extends InlineEquationView {
|
|
23
|
+
public selectNode = async () => {
|
|
24
|
+
if (!this.props.getCapabilities().editArticle) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { createEditor } = await import('../lib/codemirror')
|
|
29
|
+
|
|
30
|
+
const placeholder = 'Enter LaTeX equation, e.g. "E=mc^2"'
|
|
31
|
+
|
|
32
|
+
const input = await createEditor({
|
|
33
|
+
value: this.node.attrs.contents || '',
|
|
34
|
+
mode: 'stex',
|
|
35
|
+
placeholder,
|
|
36
|
+
autofocus: true,
|
|
37
|
+
extraKeys: {
|
|
38
|
+
Esc: () => {
|
|
39
|
+
this.props.popper.destroy()
|
|
40
|
+
this.view.focus()
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
input.on('changes', async () => {
|
|
46
|
+
const contents = input.getValue()
|
|
47
|
+
|
|
48
|
+
const pos = this.getPos()
|
|
49
|
+
|
|
50
|
+
const { tr } = this.view.state
|
|
51
|
+
const format = contents.includes('mml:math') ? 'mathml' : 'tex'
|
|
52
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
53
|
+
...this.node.attrs,
|
|
54
|
+
format,
|
|
55
|
+
contents,
|
|
56
|
+
}).setSelection(NodeSelection.create(tr.doc, pos))
|
|
57
|
+
|
|
58
|
+
this.view.dispatch(tr)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
this.props.popper.show(this.dom, input.getWrapperElement(), 'bottom')
|
|
62
|
+
|
|
63
|
+
window.requestAnimationFrame(() => {
|
|
64
|
+
input.refresh()
|
|
65
|
+
input.focus()
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default createEditableNodeView(InlineEquationEditableView)
|