@manuscripts/body-editor 3.14.0 → 3.15.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/affiliations/AffiliationsModal.js +9 -9
- package/dist/cjs/components/authors/AuthorsModal.js +9 -7
- package/dist/cjs/components/authors-affiliations/AuthorsAndAffiliationsModals.js +1 -0
- package/dist/cjs/components/cross-ref-check-modal/CrossRefWarningModal.js +182 -0
- package/dist/cjs/components/cross-ref-check-modal/openModal.js +38 -0
- package/dist/cjs/components/references/ImportBibliographyForm.js +5 -2
- package/dist/cjs/components/references/ReferenceSearch.js +2 -2
- package/dist/cjs/components/references/ReferencesModal.js +2 -2
- package/dist/cjs/plugins/affiliations.js +6 -3
- package/dist/cjs/plugins/bibliography.js +6 -3
- package/dist/cjs/plugins/cross-references.js +165 -2
- package/dist/cjs/plugins/footnotes.js +6 -3
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/embed.js +2 -2
- package/dist/cjs/views/footnote.js +2 -2
- package/dist/es/components/affiliations/AffiliationsModal.js +1 -1
- package/dist/es/components/authors/AuthorsModal.js +3 -1
- package/dist/es/components/authors-affiliations/AuthorsAndAffiliationsModals.js +1 -0
- package/dist/es/components/cross-ref-check-modal/CrossRefWarningModal.js +142 -0
- package/dist/es/components/cross-ref-check-modal/openModal.js +31 -0
- package/dist/es/components/references/ImportBibliographyForm.js +1 -1
- package/dist/es/components/references/ReferenceSearch.js +1 -1
- package/dist/es/components/references/ReferencesModal.js +1 -1
- package/dist/es/plugins/affiliations.js +1 -1
- package/dist/es/plugins/bibliography.js +1 -1
- package/dist/es/plugins/cross-references.js +163 -3
- package/dist/es/plugins/footnotes.js +1 -1
- package/dist/es/versions.js +1 -1
- package/dist/es/views/embed.js +1 -1
- package/dist/es/views/footnote.js +1 -1
- package/dist/types/components/authors-affiliations/AuthorsAndAffiliationsModals.d.ts +1 -1
- package/dist/types/components/cross-ref-check-modal/CrossRefWarningModal.d.ts +29 -0
- package/dist/types/components/cross-ref-check-modal/openModal.d.ts +19 -0
- package/dist/types/versions.d.ts +1 -1
- package/package.json +2 -2
- package/src/components/affiliations/AffiliationsModal.tsx +1 -1
- package/src/components/authors/AuthorsModal.tsx +3 -1
- package/src/components/authors-affiliations/AuthorsAndAffiliationsModals.tsx +2 -0
- package/src/components/cross-ref-check-modal/CrossRefWarningModal.tsx +223 -0
- package/src/components/cross-ref-check-modal/openModal.ts +50 -0
- package/src/components/references/ImportBibliographyForm.tsx +1 -1
- package/src/components/references/ReferenceSearch.tsx +1 -1
- package/src/components/references/ReferencesModal.tsx +1 -1
- package/src/plugins/affiliations.ts +1 -1
- package/src/plugins/bibliography.ts +1 -1
- package/src/plugins/cross-references.ts +233 -7
- package/src/plugins/footnotes.ts +1 -1
- package/src/versions.ts +1 -1
- package/src/views/embed.ts +1 -1
- package/src/views/footnote.ts +1 -1
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
17
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
21
|
exports.footnotesKey = void 0;
|
|
19
22
|
const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
|
|
20
23
|
const transform_1 = require("@manuscripts/transform");
|
|
21
|
-
const
|
|
24
|
+
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
22
25
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
23
26
|
const prosemirror_utils_1 = require("prosemirror-utils");
|
|
24
27
|
const prosemirror_view_1 = require("prosemirror-view");
|
|
@@ -99,8 +102,8 @@ const buildFootnotesElementState = (container, element) => {
|
|
|
99
102
|
const hasChanged = ($new, $old) => {
|
|
100
103
|
const nids = $new.footnotes.map(([node]) => node.attrs.id);
|
|
101
104
|
const oids = $old?.footnotes.map(([node]) => node.attrs.id);
|
|
102
|
-
return !((0,
|
|
103
|
-
(0,
|
|
105
|
+
return !((0, isEqual_1.default)(nids, oids) &&
|
|
106
|
+
(0, isEqual_1.default)($new.unusedFootnoteIDs, $old?.unusedFootnoteIDs));
|
|
104
107
|
};
|
|
105
108
|
exports.default = (props) => {
|
|
106
109
|
return new prosemirror_state_1.Plugin({
|
package/dist/cjs/versions.js
CHANGED
package/dist/cjs/views/embed.js
CHANGED
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.EmbedView = void 0;
|
|
7
|
-
const
|
|
7
|
+
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
8
8
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
9
9
|
const InsertEmbedDialog_1 = require("../components/toolbar/InsertEmbedDialog");
|
|
10
10
|
const get_media_type_1 = require("../lib/get-media-type");
|
|
@@ -101,7 +101,7 @@ class EmbedView extends block_view_1.default {
|
|
|
101
101
|
super.updateContents();
|
|
102
102
|
const { href, mimetype, mimeSubtype } = this.node.attrs;
|
|
103
103
|
const currentAttrs = { href, mimetype, mimeSubtype };
|
|
104
|
-
const contentChanged = !this.initialized || !(0,
|
|
104
|
+
const contentChanged = !this.initialized || !(0, isEqual_1.default)(this.previousAttrs, currentAttrs);
|
|
105
105
|
if (contentChanged) {
|
|
106
106
|
this.initialized = true;
|
|
107
107
|
this.previousAttrs = currentAttrs;
|
|
@@ -22,7 +22,7 @@ exports.FootnoteView = void 0;
|
|
|
22
22
|
const style_guide_1 = require("@manuscripts/style-guide");
|
|
23
23
|
const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
|
|
24
24
|
const transform_1 = require("@manuscripts/transform");
|
|
25
|
-
const
|
|
25
|
+
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
26
26
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
27
27
|
const prosemirror_utils_1 = require("prosemirror-utils");
|
|
28
28
|
const DeleteFootnoteDialog_1 = require("../components/views/DeleteFootnoteDialog");
|
|
@@ -93,7 +93,7 @@ class FootnoteView extends base_node_view_1.BaseNodeView {
|
|
|
93
93
|
fns?.inlineFootnotes.forEach(([node, pos]) => {
|
|
94
94
|
pos = tr.mapping.map(pos);
|
|
95
95
|
const rids = node.attrs.rids.filter((rid) => rid !== id);
|
|
96
|
-
if ((0,
|
|
96
|
+
if ((0, isEqual_1.default)(rids, node.attrs.rids)) {
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
99
|
if (!rids.length) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AddIcon, AffiliationPlaceholderIcon, CloseButton, InspectorTabPanel, InspectorTabPanels, InspectorTabs, outlineStyle, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, } from '@manuscripts/style-guide';
|
|
2
2
|
import { generateNodeID, schema } from '@manuscripts/transform';
|
|
3
|
-
import
|
|
3
|
+
import isEqual from 'lodash/isEqual';
|
|
4
4
|
import React, { useCallback, useEffect, useReducer, useRef, useState, } from 'react';
|
|
5
5
|
import styled from 'styled-components';
|
|
6
6
|
import { authorComparator, } from '../../lib/authors';
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { AddIcon, AuthorPlaceholderIcon, CloseButton, FormSubtitle, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, outlineStyle, ScrollableModalContent, SidebarContent, StyledModal, InspectorTabs, InspectorTabPanel, InspectorTabPanels, } from '@manuscripts/style-guide';
|
|
17
17
|
import { generateNodeID, schema } from '@manuscripts/transform';
|
|
18
|
-
import
|
|
18
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
19
|
+
import isEqual from 'lodash/isEqual';
|
|
20
|
+
import omit from 'lodash/omit';
|
|
19
21
|
import React, { useCallback, useEffect, useReducer, useRef, useState, } from 'react';
|
|
20
22
|
import styled from 'styled-components';
|
|
21
23
|
import { arrayReducer } from '../../lib/array-reducer';
|
|
@@ -74,4 +74,5 @@ export const openAuthorsAndAffiliationsModals = (pos, view, initialModal) => {
|
|
|
74
74
|
const dialog = ReactSubView(props, AuthorsAndAffiliationsModals, componentProps, state.doc, () => pos, view);
|
|
75
75
|
view.focus();
|
|
76
76
|
document.body.appendChild(dialog);
|
|
77
|
+
return dialog;
|
|
77
78
|
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import React, { useState } from 'react';
|
|
17
|
+
import { AttentionOrangeIcon, CloseButton, ModalContainer, ModalHeader, PrimaryButton, StyledModal, TertiaryButton, TextButton, } from '@manuscripts/style-guide';
|
|
18
|
+
import { startCase } from 'lodash';
|
|
19
|
+
import styled from 'styled-components';
|
|
20
|
+
export const CrossRefWarningModal = ({ onClose, xrefs, onConfirm, selectAndScrollTo }) => {
|
|
21
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
22
|
+
const handleClose = () => {
|
|
23
|
+
setIsOpen(false);
|
|
24
|
+
onClose();
|
|
25
|
+
};
|
|
26
|
+
return (React.createElement(Modal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: false, hideOverlay: true },
|
|
27
|
+
React.createElement(Container, { "data-cy": "cross-reference-warning-modal" },
|
|
28
|
+
React.createElement(ModalHeader, null,
|
|
29
|
+
React.createElement(CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
|
|
30
|
+
React.createElement(Body, null,
|
|
31
|
+
React.createElement(Title, null,
|
|
32
|
+
React.createElement(AttentionOrangeIcon, { width: 24, height: 22 }),
|
|
33
|
+
" Delete referenced content?"),
|
|
34
|
+
React.createElement("p", null, "You are deleting content referenced elsewhere in the document:"),
|
|
35
|
+
React.createElement(ScrolableItems, null, xrefs.map((group, i) => (React.createElement(XrefGroupDisplay, { key: i, group: group, selectAndScrollTo: selectAndScrollTo })))),
|
|
36
|
+
React.createElement(Actions, null,
|
|
37
|
+
React.createElement(TertiaryButton, { type: "button", onClick: () => handleClose() }, "Cancel"),
|
|
38
|
+
React.createElement(PrimaryButton, { "$danger": true, type: "button", onClick: () => {
|
|
39
|
+
onConfirm();
|
|
40
|
+
setIsOpen(false);
|
|
41
|
+
} }, "Delete & remove citation"))))));
|
|
42
|
+
};
|
|
43
|
+
const XrefGroupDisplay = ({ group, selectAndScrollTo }) => {
|
|
44
|
+
return (React.createElement("div", null,
|
|
45
|
+
React.createElement("h3", null, group.label),
|
|
46
|
+
React.createElement(ReferencesList, null, group.xrefs.map(([, pos], i) => {
|
|
47
|
+
return (React.createElement("li", { key: i },
|
|
48
|
+
React.createElement(TextButton, { onClick: () => selectAndScrollTo(pos) }, `${startCase(pos.parent.type.name)} - ${pos.parent.textContent}`)));
|
|
49
|
+
}))));
|
|
50
|
+
};
|
|
51
|
+
const Container = styled(ModalContainer) `
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: 1rem;
|
|
54
|
+
left: 50%;
|
|
55
|
+
right: 0;
|
|
56
|
+
max-height: calc(50vh - 2rem);
|
|
57
|
+
min-height: 280px;
|
|
58
|
+
transform: translate(-50%, 0);
|
|
59
|
+
max-width: 480px;
|
|
60
|
+
transition:
|
|
61
|
+
top 0.2s,
|
|
62
|
+
transform 0.2s;
|
|
63
|
+
`;
|
|
64
|
+
const Modal = styled(StyledModal) `
|
|
65
|
+
position: fixed;
|
|
66
|
+
top: 0;
|
|
67
|
+
left: 0;
|
|
68
|
+
width: 100%;
|
|
69
|
+
height: 100%;
|
|
70
|
+
z-index: 1100;
|
|
71
|
+
color: #6e6e6e;
|
|
72
|
+
margin: auto;
|
|
73
|
+
|
|
74
|
+
&.modal-bottom ${Container} {
|
|
75
|
+
top: calc(100% - 2rem);
|
|
76
|
+
transform: translate(-50%, -100%);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&:after {
|
|
80
|
+
content: '';
|
|
81
|
+
display: block;
|
|
82
|
+
position: fixed;
|
|
83
|
+
z-index: -1;
|
|
84
|
+
left: 0;
|
|
85
|
+
top: 0;
|
|
86
|
+
right: 0;
|
|
87
|
+
bottom: 0;
|
|
88
|
+
background: rgba(0, 0, 0, 0.2);
|
|
89
|
+
}
|
|
90
|
+
h3 {
|
|
91
|
+
font-size: 16px;
|
|
92
|
+
margin: 0.5em 0;
|
|
93
|
+
}
|
|
94
|
+
p {
|
|
95
|
+
margin: 0.5em 0;
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
const Body = styled.div `
|
|
99
|
+
margin: 1.5rem;
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-flow: column;
|
|
102
|
+
`;
|
|
103
|
+
const Title = styled.h2 `
|
|
104
|
+
font-size: 18px;
|
|
105
|
+
font-weight: 700;
|
|
106
|
+
line-height: 1.5;
|
|
107
|
+
margin: 0;
|
|
108
|
+
color: #353535;
|
|
109
|
+
svg {
|
|
110
|
+
vertical-align: text-top;
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
113
|
+
const ReferencesList = styled.ul `
|
|
114
|
+
padding: 8px;
|
|
115
|
+
margin-left: 0;
|
|
116
|
+
list-style: none;
|
|
117
|
+
background: #f2f2f2;
|
|
118
|
+
border: 1px solid #e2e2e2;
|
|
119
|
+
border-radius: 3px;
|
|
120
|
+
|
|
121
|
+
${TextButton} {
|
|
122
|
+
margin-left: 0;
|
|
123
|
+
text-decoration: underline;
|
|
124
|
+
&:hover {
|
|
125
|
+
text-decoration: none;
|
|
126
|
+
}
|
|
127
|
+
display: block;
|
|
128
|
+
max-width: 100%;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
color: #353535;
|
|
131
|
+
text-overflow: ellipsis;
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
const Actions = styled.footer `
|
|
135
|
+
text-align: right;
|
|
136
|
+
padding-top: 1rem;
|
|
137
|
+
`;
|
|
138
|
+
const ScrolableItems = styled.div `
|
|
139
|
+
max-height: 16vh;
|
|
140
|
+
min-height: 100px;
|
|
141
|
+
overflow-y: auto;
|
|
142
|
+
`;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { getEditorProps } from '../../plugins/editor-props';
|
|
17
|
+
import ReactSubView from '../../views/ReactSubView';
|
|
18
|
+
import { CrossRefWarningModal } from './CrossRefWarningModal';
|
|
19
|
+
export const openCrossRefWarningModal = (view, xrefGroups, onConfirm, onClose, selectAndScrollTo) => {
|
|
20
|
+
const { state } = view;
|
|
21
|
+
const props = getEditorProps(state);
|
|
22
|
+
const componentProps = {
|
|
23
|
+
xrefs: xrefGroups,
|
|
24
|
+
onConfirm,
|
|
25
|
+
onClose,
|
|
26
|
+
selectAndScrollTo,
|
|
27
|
+
};
|
|
28
|
+
const dialog = ReactSubView(props, CrossRefWarningModal, componentProps, state.doc, () => 0, view);
|
|
29
|
+
document.body.appendChild(dialog);
|
|
30
|
+
return dialog;
|
|
31
|
+
};
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { FormActionsBar, FormRow, Label, outlineStyle, PrimaryButton, SecondaryButton, TextArea, } from '@manuscripts/style-guide';
|
|
17
17
|
import { useFormik } from 'formik';
|
|
18
|
-
import
|
|
18
|
+
import debounce from 'lodash/debounce';
|
|
19
19
|
import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
20
20
|
import styled, { css } from 'styled-components';
|
|
21
21
|
import { importBibliographyItems } from '../../lib/references';
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, UploadIcon, withFocusTrap, } from '@manuscripts/style-guide';
|
|
17
|
-
import
|
|
17
|
+
import debounce from 'lodash/debounce';
|
|
18
18
|
import React, { useState } from 'react';
|
|
19
19
|
import styled from 'styled-components';
|
|
20
20
|
import { DocumentReferenceSource, } from './BibliographyItemSource';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
|
|
2
|
-
import
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
3
3
|
import React, { useEffect, useRef, useState } from 'react';
|
|
4
4
|
import styled from 'styled-components';
|
|
5
5
|
import { ReferenceForm, } from './ReferenceForm/ReferenceForm';
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { isDeleted } from '@manuscripts/track-changes-plugin';
|
|
17
17
|
import { isAffiliationNode, isContributorNode, } from '@manuscripts/transform';
|
|
18
|
-
import
|
|
18
|
+
import isEqual from 'lodash/isEqual';
|
|
19
19
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
20
20
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
21
21
|
import { authorComparator, } from '../lib/authors';
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { buildCiteprocCitation, isBibliographyElementNode, isBibliographyItemNode, isCitationNode, } from '@manuscripts/transform';
|
|
17
17
|
import * as Citeproc from 'citeproc';
|
|
18
|
-
import
|
|
18
|
+
import isEqual from 'lodash/isEqual';
|
|
19
19
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
20
20
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
21
21
|
export const bibliographyKey = new PluginKey('bibliography');
|
|
@@ -13,13 +13,62 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { schema } from '@manuscripts/transform';
|
|
17
|
-
import {
|
|
18
|
-
import
|
|
16
|
+
import { schema, } from '@manuscripts/transform';
|
|
17
|
+
import { trackChangesPluginKey } from '@manuscripts/track-changes-plugin';
|
|
18
|
+
import isEqual from 'lodash/isEqual';
|
|
19
|
+
import { NodeSelection, Plugin } from 'prosemirror-state';
|
|
19
20
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
21
|
+
import { openCrossRefWarningModal } from '../components/cross-ref-check-modal/openModal';
|
|
20
22
|
import { objectsKey } from './objects';
|
|
23
|
+
let modalActive = false;
|
|
24
|
+
let modalElement = null;
|
|
21
25
|
export default () => {
|
|
26
|
+
let view = null;
|
|
22
27
|
return new Plugin({
|
|
28
|
+
view(editorView) {
|
|
29
|
+
view = editorView;
|
|
30
|
+
return {
|
|
31
|
+
update(v) {
|
|
32
|
+
view = v;
|
|
33
|
+
},
|
|
34
|
+
destroy() {
|
|
35
|
+
view = null;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
filterTransaction(tr, state) {
|
|
40
|
+
if (!view ||
|
|
41
|
+
!tr.docChanged ||
|
|
42
|
+
tr.getMeta(trackChangesPluginKey) ||
|
|
43
|
+
tr.getMeta('addToHistory') === false) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (modalActive) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const targets = objectsKey.getState(state);
|
|
50
|
+
const xrefGroups = createXrefGroups(targets, state.doc, tr.doc);
|
|
51
|
+
if (xrefGroups.length === 0) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
modalActive = true;
|
|
55
|
+
const cleanup = () => {
|
|
56
|
+
modalActive = false;
|
|
57
|
+
if (modalElement) {
|
|
58
|
+
modalElement.classList.remove('modal-bottom');
|
|
59
|
+
modalElement.remove();
|
|
60
|
+
modalElement = null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const deletedIds = new Set(xrefGroups.map((g) => g.referenced.attrs.id));
|
|
64
|
+
const onClose = () => {
|
|
65
|
+
cleanup();
|
|
66
|
+
};
|
|
67
|
+
if (view) {
|
|
68
|
+
modalElement = openCrossRefWarningModal(view, xrefGroups, onConfirmCreator(view, cleanup, deletedIds, tr), onClose, selectAndScrollToCreator(view));
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
},
|
|
23
72
|
state: {
|
|
24
73
|
init() {
|
|
25
74
|
return DecorationSet.empty;
|
|
@@ -53,3 +102,114 @@ function createDecorations(doc) {
|
|
|
53
102
|
});
|
|
54
103
|
return decorations;
|
|
55
104
|
}
|
|
105
|
+
function createXrefGroups(targets, stateDoc, resultDoc) {
|
|
106
|
+
const newIds = new Set();
|
|
107
|
+
const xrefRids = new Set();
|
|
108
|
+
const xrefGroups = [];
|
|
109
|
+
resultDoc.descendants((node) => {
|
|
110
|
+
if (node.attrs.id) {
|
|
111
|
+
newIds.add(node.attrs.id);
|
|
112
|
+
}
|
|
113
|
+
if (node.type === schema.nodes.cross_reference) {
|
|
114
|
+
for (const rid of node.attrs.rids) {
|
|
115
|
+
xrefRids.add(rid);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
const orphanedRids = new Set();
|
|
120
|
+
for (const rid of xrefRids) {
|
|
121
|
+
if (!newIds.has(rid)) {
|
|
122
|
+
orphanedRids.add(rid);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (orphanedRids.size === 0) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
const referencedNodes = new Map();
|
|
129
|
+
const xrefsByRid = new Map();
|
|
130
|
+
stateDoc.descendants((node, pos) => {
|
|
131
|
+
const id = node.attrs.id;
|
|
132
|
+
if (id && orphanedRids.has(id)) {
|
|
133
|
+
referencedNodes.set(id, node);
|
|
134
|
+
}
|
|
135
|
+
if (node.type === schema.nodes.cross_reference) {
|
|
136
|
+
for (const rid of node.attrs.rids) {
|
|
137
|
+
if (orphanedRids.has(rid)) {
|
|
138
|
+
let entries = xrefsByRid.get(rid);
|
|
139
|
+
if (!entries) {
|
|
140
|
+
entries = [];
|
|
141
|
+
xrefsByRid.set(rid, entries);
|
|
142
|
+
}
|
|
143
|
+
entries.push([node, stateDoc.resolve(pos)]);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
for (const [id, referenced] of referencedNodes) {
|
|
149
|
+
const xrefs = xrefsByRid.get(id);
|
|
150
|
+
if (xrefs?.length) {
|
|
151
|
+
const label = targets.get(referenced.attrs.id)?.label || '';
|
|
152
|
+
xrefGroups.push({ referenced, label, xrefs });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return xrefGroups;
|
|
156
|
+
}
|
|
157
|
+
const onConfirmCreator = (view, cleanup, deletedIds, tr) => () => {
|
|
158
|
+
cleanup();
|
|
159
|
+
if (!view) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const newTr = view.state.tr;
|
|
163
|
+
for (const step of tr.steps) {
|
|
164
|
+
const result = step.apply(newTr.doc);
|
|
165
|
+
if (result.failed) {
|
|
166
|
+
console.warn('Cross-ref deletion warning: could not replay step —', result.failed);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
newTr.step(step);
|
|
170
|
+
}
|
|
171
|
+
const xrefPositions = [];
|
|
172
|
+
newTr.doc.descendants((node, pos) => {
|
|
173
|
+
if (node.type === schema.nodes.cross_reference) {
|
|
174
|
+
const rids = node.attrs.rids;
|
|
175
|
+
if (rids.some((rid) => deletedIds.has(rid))) {
|
|
176
|
+
xrefPositions.push({ from: pos, to: pos + node.nodeSize });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
for (let i = xrefPositions.length - 1; i >= 0; i--) {
|
|
181
|
+
const { from, to } = xrefPositions[i];
|
|
182
|
+
newTr.delete(from, to);
|
|
183
|
+
}
|
|
184
|
+
view.dispatch(newTr);
|
|
185
|
+
};
|
|
186
|
+
const selectAndScrollToCreator = (view) => ($pos) => {
|
|
187
|
+
if (!view) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const selTr = view.state.tr;
|
|
191
|
+
selTr.setSelection(NodeSelection.create(view.state.doc, $pos.pos));
|
|
192
|
+
view.focus();
|
|
193
|
+
view.dispatch(selTr);
|
|
194
|
+
let scrollable = view.dom.parentElement;
|
|
195
|
+
while (scrollable != null &&
|
|
196
|
+
scrollable.scrollHeight <= scrollable.clientHeight) {
|
|
197
|
+
scrollable = scrollable.parentElement;
|
|
198
|
+
}
|
|
199
|
+
if (!scrollable) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const coords = view.coordsAtPos($pos.pos);
|
|
203
|
+
const containerRect = scrollable.getBoundingClientRect();
|
|
204
|
+
const offsetInContainer = coords.top - containerRect.top + scrollable.scrollTop;
|
|
205
|
+
const containerHeight = scrollable.clientHeight;
|
|
206
|
+
const scrollTo = offsetInContainer - containerHeight * 0.75;
|
|
207
|
+
if (scrollTo < 0) {
|
|
208
|
+
modalElement?.classList.add('modal-bottom');
|
|
209
|
+
scrollable.scrollTo({ top: 0, behavior: 'smooth' });
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
modalElement?.classList.remove('modal-bottom');
|
|
213
|
+
scrollable.scrollTo({ top: scrollTo, behavior: 'smooth' });
|
|
214
|
+
}
|
|
215
|
+
};
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { skipTracking } from '@manuscripts/track-changes-plugin';
|
|
17
17
|
import { generateAlphaFootnoteLabel, isTableElementNode, schema, } from '@manuscripts/transform';
|
|
18
|
-
import
|
|
18
|
+
import isEqual from 'lodash/isEqual';
|
|
19
19
|
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
|
|
20
20
|
import { findChildrenByType } from 'prosemirror-utils';
|
|
21
21
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
package/dist/es/versions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '3.
|
|
1
|
+
export const VERSION = '3.15.1';
|
|
2
2
|
export const MATHJAX_VERSION = '3.2.2';
|
package/dist/es/views/embed.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isEqual from 'lodash/isEqual';
|
|
2
2
|
import { NodeSelection } from 'prosemirror-state';
|
|
3
3
|
import { NoPreviewMessageWithLink, openEmbedDialog, } from '../components/toolbar/InsertEmbedDialog';
|
|
4
4
|
import { getMediaTypeInfo } from '../lib/get-media-type';
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { ContextMenu } from '@manuscripts/style-guide';
|
|
17
17
|
import { isDeleted, isPendingInsert } from '@manuscripts/track-changes-plugin';
|
|
18
18
|
import { schema } from '@manuscripts/transform';
|
|
19
|
-
import
|
|
19
|
+
import isEqual from 'lodash/isEqual';
|
|
20
20
|
import { NodeSelection } from 'prosemirror-state';
|
|
21
21
|
import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
|
|
22
22
|
import { DeleteFootnoteDialog, } from '../components/views/DeleteFootnoteDialog';
|
|
@@ -26,4 +26,4 @@ export interface AuthorsAndAffiliationsModalsProps {
|
|
|
26
26
|
addNewAffiliation?: boolean;
|
|
27
27
|
}
|
|
28
28
|
export declare const AuthorsAndAffiliationsModals: React.FC<AuthorsAndAffiliationsModalsProps>;
|
|
29
|
-
export declare const openAuthorsAndAffiliationsModals: (pos: number, view: ManuscriptEditorView | EditorView | undefined, initialModal: "authors" | "affiliations") =>
|
|
29
|
+
export declare const openAuthorsAndAffiliationsModals: (pos: number, view: ManuscriptEditorView | EditorView | undefined, initialModal: "authors" | "affiliations") => HTMLDivElement | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { ManuscriptNode } from '@manuscripts/transform';
|
|
17
|
+
import React from 'react';
|
|
18
|
+
import { ResolvedPos } from 'prosemirror-model';
|
|
19
|
+
export type XrefGroup = {
|
|
20
|
+
referenced: ManuscriptNode;
|
|
21
|
+
label: string;
|
|
22
|
+
xrefs: [ManuscriptNode, ResolvedPos][];
|
|
23
|
+
};
|
|
24
|
+
export declare const CrossRefWarningModal: React.FC<{
|
|
25
|
+
onClose: () => void;
|
|
26
|
+
xrefs: XrefGroup[];
|
|
27
|
+
onConfirm: () => void;
|
|
28
|
+
selectAndScrollTo: ($pos: ResolvedPos) => void;
|
|
29
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { ManuscriptEditorView } from '@manuscripts/transform';
|
|
17
|
+
import { ResolvedPos } from 'prosemirror-model';
|
|
18
|
+
import { XrefGroup } from './CrossRefWarningModal';
|
|
19
|
+
export declare const openCrossRefWarningModal: (view: ManuscriptEditorView, xrefGroups: XrefGroup[], onConfirm: () => void, onClose: () => void, selectAndScrollTo: ($pos: ResolvedPos) => void) => HTMLDivElement;
|
package/dist/types/versions.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "3.
|
|
1
|
+
export declare const VERSION = "3.15.1";
|
|
2
2
|
export declare const MATHJAX_VERSION = "3.2.2";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manuscripts/body-editor",
|
|
3
3
|
"description": "Prosemirror components for editing and viewing manuscripts",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.15.1",
|
|
5
5
|
"repository": "github:Atypon-OpenSource/manuscripts-body-editor",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "dist/cjs",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"jest": "30.4.2",
|
|
109
109
|
"jest-environment-jsdom": "30.4.1",
|
|
110
110
|
"jest-prosemirror": "3.0.1",
|
|
111
|
-
"npm-run-all2": "
|
|
111
|
+
"npm-run-all2": "8.0.4",
|
|
112
112
|
"prettier": "3.8.3",
|
|
113
113
|
"regenerator-runtime": "0.14.1",
|
|
114
114
|
"rimraf": "6.1.3",
|
|
@@ -34,7 +34,9 @@ import {
|
|
|
34
34
|
InspectorTabPanels,
|
|
35
35
|
} from '@manuscripts/style-guide'
|
|
36
36
|
import { generateNodeID, schema } from '@manuscripts/transform'
|
|
37
|
-
import
|
|
37
|
+
import cloneDeep from 'lodash/cloneDeep'
|
|
38
|
+
import isEqual from 'lodash/isEqual'
|
|
39
|
+
import omit from 'lodash/omit'
|
|
38
40
|
import React, {
|
|
39
41
|
useCallback,
|
|
40
42
|
useEffect,
|