@manuscripts/body-editor 3.2.4 → 3.2.6

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.
@@ -64,8 +64,15 @@ const ReferenceForm = ({ values, showDelete, onChange, onDelete, onCancel, onSav
64
64
  const [showDeleteDialog, setShowDeleteDialog] = (0, react_1.useState)(false);
65
65
  const validateReference = (values) => {
66
66
  const errors = {};
67
- if (!values.title?.trim()) {
68
- errors.title = 'Title is required';
67
+ if (values.type === 'literal') {
68
+ if (!values.literal?.trim()) {
69
+ errors.literal = 'Literal is required for unstructured references';
70
+ }
71
+ }
72
+ else {
73
+ if (!values.title?.trim()) {
74
+ errors.title = 'Title is required';
75
+ }
69
76
  }
70
77
  return errors;
71
78
  };
@@ -110,6 +117,10 @@ const ReferenceForm = ({ values, showDelete, onChange, onDelete, onCancel, onSav
110
117
  react_1.default.createElement(styled_components_1.LabelContainer, null,
111
118
  react_1.default.createElement(styled_components_1.Label, null, "Title")),
112
119
  react_1.default.createElement(formik_1.Field, { name: 'title' }, (props) => (react_1.default.createElement(styled_components_1.ReferenceTextArea, { id: 'title', ...props.field }))))),
120
+ (0, utils_1.shouldRenderField)('literal', formik.values.type) && (react_1.default.createElement(styled_components_1.FormField, null,
121
+ react_1.default.createElement(styled_components_1.LabelContainer, null,
122
+ react_1.default.createElement(styled_components_1.Label, null, "Text")),
123
+ react_1.default.createElement(formik_1.Field, { name: 'literal' }, (props) => (react_1.default.createElement(styled_components_1.ReferenceTextArea, { id: 'literal', ...props.field }))))),
113
124
  (0, utils_1.shouldRenderField)('std', formik.values.type) && (react_1.default.createElement(styled_components_1.FormField, null,
114
125
  react_1.default.createElement(styled_components_1.LabelContainer, null,
115
126
  react_1.default.createElement(styled_components_1.Label, { htmlFor: 'std' }, "Standard")),
@@ -32,6 +32,6 @@ exports.MetadataContainer = styled_components_1.default.div `
32
32
  flex: 1;
33
33
  `;
34
34
  const ReferenceLine = ({ item }) => (react_1.default.createElement(exports.MetadataContainer, null,
35
- react_1.default.createElement("div", { "data-cy": 'reference-title' }, item.title || 'Untitled'),
35
+ react_1.default.createElement("div", { "data-cy": 'reference-title' }, item.title || item.literal || 'Untitled'),
36
36
  react_1.default.createElement(exports.Metadata, null, (0, references_1.metadata)(item))));
37
37
  exports.ReferenceLine = ReferenceLine;
@@ -7,27 +7,33 @@ exports.FigureOptions = void 0;
7
7
  const style_guide_1 = require("@manuscripts/style-guide");
8
8
  const react_1 = __importDefault(require("react"));
9
9
  const styled_components_1 = __importDefault(require("styled-components"));
10
- const FigureOptions = ({ can, files, onDownload, onUpload, onDetach, onReplace, onDelete, }) => {
11
- const { isOpen, toggleOpen, wrapperRef } = (0, style_guide_1.useDropdown)();
12
- const supplements = files.supplements
13
- .map((s) => s.file)
10
+ const files_1 = require("../../lib/files");
11
+ function getSupplements(getFiles, getDoc, groupFiles) {
12
+ return groupFiles(getDoc(), getFiles())
13
+ .supplements.map((s) => s.file)
14
14
  .filter((f) => (0, style_guide_1.isImageFile)(f.name));
15
- const otherFiles = files.others.filter((f) => (0, style_guide_1.isImageFile)(f.name));
15
+ }
16
+ function getOtherFiles(getFiles, getDoc, groupFiles) {
17
+ return groupFiles(getDoc(), getFiles()).others.filter((f) => (0, style_guide_1.isImageFile)(f.name));
18
+ }
19
+ const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onDetach, onReplace, onDelete, }) => {
20
+ const { isOpen, toggleOpen, wrapperRef } = (0, style_guide_1.useDropdown)();
16
21
  const showDownload = onDownload && can.downloadFiles;
17
22
  const showUpload = onUpload && can.uploadFile;
18
23
  const showDetach = onDetach && can.detachFile;
19
24
  const showReplace = onReplace && can.replaceFile;
20
25
  const replaceBtnText = onDownload ? 'Replace' : 'Choose file';
21
26
  const showDelete = onDelete && can.detachFile;
27
+ const groupFiles = (0, files_1.memoGroupFiles)();
22
28
  return (react_1.default.createElement(DropdownWrapper, { ref: wrapperRef },
23
29
  react_1.default.createElement(OptionsButton, { className: 'options-button', onClick: toggleOpen },
24
30
  react_1.default.createElement(style_guide_1.DotsIcon, null)),
25
31
  isOpen && (react_1.default.createElement(OptionsDropdownList, { direction: 'right', width: 128, top: 5 },
26
32
  react_1.default.createElement(NestedDropdown, { disabled: !showReplace, parentToggleOpen: toggleOpen, buttonText: replaceBtnText, moveLeft: true, list: react_1.default.createElement(react_1.default.Fragment, null,
27
- supplements.map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
33
+ getSupplements(getFiles, getDoc, groupFiles).map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
28
34
  (0, style_guide_1.getFileIcon)(file.name),
29
35
  react_1.default.createElement(ListItemText, null, file.name)))),
30
- otherFiles.map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
36
+ getOtherFiles(getFiles, getDoc, groupFiles).map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
31
37
  (0, style_guide_1.getFileIcon)(file.name),
32
38
  react_1.default.createElement(ListItemText, null, file.name)))),
33
39
  react_1.default.createElement(UploadButton, { onClick: onUpload, disabled: !showUpload },
@@ -58,7 +58,7 @@ exports.default = (props) => {
58
58
  (0, track_changes_plugin_1.trackChangesPlugin)({
59
59
  userID: props.userID,
60
60
  debug: props.debug,
61
- initialStatus: props.isViewingMode
61
+ initialStatus: props.isViewingMode || props.isComparingMode
62
62
  ? track_changes_plugin_1.TrackChangesStatus.viewSnapshots
63
63
  : props.getCapabilities().editWithoutTracking
64
64
  ? track_changes_plugin_1.TrackChangesStatus.disabled
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.groupFiles = void 0;
3
+ exports.groupFiles = exports.memoGroupFiles = void 0;
4
4
  const transform_1 = require("@manuscripts/transform");
5
5
  const prosemirror_utils_1 = require("prosemirror-utils");
6
6
  const track_changes_utils_1 = require("./track-changes-utils");
@@ -13,6 +13,20 @@ const figureTypes = [
13
13
  transform_1.schema.nodes.image_element,
14
14
  transform_1.schema.nodes.hero_image,
15
15
  ];
16
+ function memoGroupFiles() {
17
+ let prevFiles = [];
18
+ let prevDoc = undefined;
19
+ let result;
20
+ return function (doc, files) {
21
+ if (result && prevDoc === doc && prevFiles === files) {
22
+ return result;
23
+ }
24
+ prevDoc = doc;
25
+ prevFiles = files;
26
+ return (0, exports.groupFiles)(doc, files);
27
+ };
28
+ }
29
+ exports.memoGroupFiles = memoGroupFiles;
16
30
  const groupFiles = (doc, files) => {
17
31
  const fileMap = new Map(files.map((f) => [f.id, f]));
18
32
  const figures = [];
@@ -88,5 +88,5 @@ exports.bibliographyItemTypes = [
88
88
  ['standard', 'Standard'],
89
89
  ['dataset', 'Dataset'],
90
90
  ['preprint', 'Preprint'],
91
- ['literal', 'Literal'],
91
+ ['literal', 'Unstructured'],
92
92
  ];
@@ -31,7 +31,14 @@ const useEditor = (externalProps) => {
31
31
  const [state, setState] = (0, react_1.useState)(() => (0, ManuscriptsEditor_1.createEditorState)(props));
32
32
  const location = (0, react_router_dom_1.useLocation)();
33
33
  const { collabProvider } = props;
34
- if (collabProvider) {
34
+ (0, react_1.useEffect)(() => {
35
+ if (view.current && props.isComparingMode) {
36
+ const newState = (0, ManuscriptsEditor_1.createEditorState)(props);
37
+ setState(newState);
38
+ view.current.updateState(newState);
39
+ }
40
+ }, [props.doc, props.isComparingMode]);
41
+ if (collabProvider && !props.isComparingMode) {
35
42
  collabProvider.onNewSteps(async () => {
36
43
  if (state && view.current) {
37
44
  const localVersion = (0, prosemirror_collab_1.getVersion)(view.current.state);
@@ -57,7 +64,9 @@ const useEditor = (externalProps) => {
57
64
  view.current.updateState(nextState);
58
65
  const trackState = track_changes_plugin_1.trackChangesPluginKey.getState(view.current.state);
59
66
  if (collabProvider &&
60
- (!trackState || trackState.status !== track_changes_plugin_1.TrackChangesStatus.viewSnapshots)) {
67
+ (!trackState ||
68
+ trackState.status !== track_changes_plugin_1.TrackChangesStatus.viewSnapshots) &&
69
+ !props.isComparingMode) {
61
70
  const sendable = (0, prosemirror_collab_1.sendableSteps)(nextState);
62
71
  if (sendable) {
63
72
  collabProvider.sendSteps(sendable.version, sendable.steps, sendable.clientID, false);
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MATHJAX_VERSION = exports.VERSION = void 0;
4
- exports.VERSION = '3.2.4';
4
+ exports.VERSION = '3.2.6';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -174,8 +174,28 @@ class BibliographyElementBlockView extends block_view_1.default {
174
174
  for (let i = 0; i < bibliography.length; i++) {
175
175
  const id = meta.entry_ids[i][0];
176
176
  const fragment = bibliography[i];
177
- const element = (0, dompurify_1.sanitize)(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${fragment}</div></div>`).firstElementChild;
178
177
  const node = nodes.get(id);
178
+ const isUnstructured = node.attrs.type === 'literal';
179
+ const tempDiv = document.createElement('div');
180
+ tempDiv.innerHTML = fragment;
181
+ if (isUnstructured) {
182
+ const cslLeftMarginDiv = tempDiv.querySelector('.csl-left-margin');
183
+ let cslRightInlineDiv = tempDiv.querySelector('.csl-right-inline');
184
+ const cslEntry = tempDiv.querySelector('.csl-entry');
185
+ if (cslRightInlineDiv) {
186
+ cslRightInlineDiv.textContent = node.attrs.literal ?? '';
187
+ }
188
+ else if (cslLeftMarginDiv) {
189
+ cslRightInlineDiv = document.createElement('div');
190
+ cslRightInlineDiv.classList.add('csl-right-inline');
191
+ cslRightInlineDiv.textContent = node.attrs.literal ?? '';
192
+ cslLeftMarginDiv.after(cslRightInlineDiv);
193
+ }
194
+ else if (cslEntry) {
195
+ cslEntry.textContent = node.attrs.literal ?? '';
196
+ }
197
+ }
198
+ const element = (0, dompurify_1.sanitize)(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${tempDiv.innerHTML}</div></div>`).firstElementChild;
179
199
  const comment = (0, comments_1.createCommentMarker)('div', id);
180
200
  element.prepend(comment);
181
201
  (0, track_changes_utils_1.addTrackChangesAttributes)(node.attrs, element);
@@ -41,7 +41,11 @@ class CitationView extends base_node_view_1.BaseNodeView {
41
41
  }
42
42
  const id = this.node.attrs.id;
43
43
  const text = bib.renderedCitations.get(id);
44
- const fragment = (0, dompurify_1.sanitize)(text && text !== '[NO_PRINTED_FORM]' ? text : ' ', {
44
+ const fragment = (0, dompurify_1.sanitize)(text === '(n.d.)'
45
+ ? 'Missing citation data'
46
+ : text && text !== '[NO_PRINTED_FORM]'
47
+ ? text
48
+ : ' ', {
45
49
  ALLOWED_TAGS: ['i', 'b', 'span', 'sup', 'sub', '#text'],
46
50
  });
47
51
  this.dom.innerHTML = '';
@@ -134,10 +134,9 @@ class ContributorsView extends block_view_1.default {
134
134
  action: () => this.handleEdit(''),
135
135
  icon: 'Edit',
136
136
  });
137
- this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu']);
138
- return this.contextMenu;
139
137
  }
140
- return undefined;
138
+ this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu']);
139
+ return this.contextMenu;
141
140
  };
142
141
  this.actionGutterButtons = () => {
143
142
  const contextMenu = this.authorContextMenu();
@@ -26,7 +26,6 @@ const prosemirror_utils_1 = require("prosemirror-utils");
26
26
  const react_1 = require("react");
27
27
  const server_1 = require("react-dom/server");
28
28
  const FigureDropdown_1 = require("../components/views/FigureDropdown");
29
- const files_1 = require("../lib/files");
30
29
  const track_changes_utils_1 = require("../lib/track-changes-utils");
31
30
  const view_1 = require("../lib/view");
32
31
  const creators_1 = require("./creators");
@@ -295,11 +294,10 @@ class FigureEditableView extends figure_1.FigureView {
295
294
  }
296
295
  this.reactTools?.remove();
297
296
  if (this.props.dispatch && this.props.theme) {
298
- const files = this.props.getFiles();
299
- const doc = this.view.state.doc;
300
297
  const componentProps = {
301
298
  can,
302
- files: (0, files_1.groupFiles)(doc, files),
299
+ getDoc: () => this.view.state.doc,
300
+ getFiles: this.props.getFiles,
303
301
  onDownload: handleDownload,
304
302
  onUpload: handleUpload,
305
303
  onDetach: handleDetach,
@@ -38,8 +38,15 @@ export const ReferenceForm = ({ values, showDelete, onChange, onDelete, onCancel
38
38
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
39
39
  const validateReference = (values) => {
40
40
  const errors = {};
41
- if (!values.title?.trim()) {
42
- errors.title = 'Title is required';
41
+ if (values.type === 'literal') {
42
+ if (!values.literal?.trim()) {
43
+ errors.literal = 'Literal is required for unstructured references';
44
+ }
45
+ }
46
+ else {
47
+ if (!values.title?.trim()) {
48
+ errors.title = 'Title is required';
49
+ }
43
50
  }
44
51
  return errors;
45
52
  };
@@ -84,6 +91,10 @@ export const ReferenceForm = ({ values, showDelete, onChange, onDelete, onCancel
84
91
  React.createElement(LabelContainer, null,
85
92
  React.createElement(Label, null, "Title")),
86
93
  React.createElement(Field, { name: 'title' }, (props) => (React.createElement(ReferenceTextArea, { id: 'title', ...props.field }))))),
94
+ shouldRenderField('literal', formik.values.type) && (React.createElement(FormField, null,
95
+ React.createElement(LabelContainer, null,
96
+ React.createElement(Label, null, "Text")),
97
+ React.createElement(Field, { name: 'literal' }, (props) => (React.createElement(ReferenceTextArea, { id: 'literal', ...props.field }))))),
87
98
  shouldRenderField('std', formik.values.type) && (React.createElement(FormField, null,
88
99
  React.createElement(LabelContainer, null,
89
100
  React.createElement(Label, { htmlFor: 'std' }, "Standard")),
@@ -26,5 +26,5 @@ export const MetadataContainer = styled.div `
26
26
  flex: 1;
27
27
  `;
28
28
  export const ReferenceLine = ({ item }) => (React.createElement(MetadataContainer, null,
29
- React.createElement("div", { "data-cy": 'reference-title' }, item.title || 'Untitled'),
29
+ React.createElement("div", { "data-cy": 'reference-title' }, item.title || item.literal || 'Untitled'),
30
30
  React.createElement(Metadata, null, metadata(item))));
@@ -1,27 +1,33 @@
1
1
  import { DotsIcon, DropdownList, getFileIcon, IconButton, IconTextButton, isImageFile, TriangleCollapsedIcon, UploadIcon, useDropdown, } from '@manuscripts/style-guide';
2
2
  import React from 'react';
3
3
  import styled from 'styled-components';
4
- export const FigureOptions = ({ can, files, onDownload, onUpload, onDetach, onReplace, onDelete, }) => {
5
- const { isOpen, toggleOpen, wrapperRef } = useDropdown();
6
- const supplements = files.supplements
7
- .map((s) => s.file)
4
+ import { memoGroupFiles, } from '../../lib/files';
5
+ function getSupplements(getFiles, getDoc, groupFiles) {
6
+ return groupFiles(getDoc(), getFiles())
7
+ .supplements.map((s) => s.file)
8
8
  .filter((f) => isImageFile(f.name));
9
- const otherFiles = files.others.filter((f) => isImageFile(f.name));
9
+ }
10
+ function getOtherFiles(getFiles, getDoc, groupFiles) {
11
+ return groupFiles(getDoc(), getFiles()).others.filter((f) => isImageFile(f.name));
12
+ }
13
+ export const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onDetach, onReplace, onDelete, }) => {
14
+ const { isOpen, toggleOpen, wrapperRef } = useDropdown();
10
15
  const showDownload = onDownload && can.downloadFiles;
11
16
  const showUpload = onUpload && can.uploadFile;
12
17
  const showDetach = onDetach && can.detachFile;
13
18
  const showReplace = onReplace && can.replaceFile;
14
19
  const replaceBtnText = onDownload ? 'Replace' : 'Choose file';
15
20
  const showDelete = onDelete && can.detachFile;
21
+ const groupFiles = memoGroupFiles();
16
22
  return (React.createElement(DropdownWrapper, { ref: wrapperRef },
17
23
  React.createElement(OptionsButton, { className: 'options-button', onClick: toggleOpen },
18
24
  React.createElement(DotsIcon, null)),
19
25
  isOpen && (React.createElement(OptionsDropdownList, { direction: 'right', width: 128, top: 5 },
20
26
  React.createElement(NestedDropdown, { disabled: !showReplace, parentToggleOpen: toggleOpen, buttonText: replaceBtnText, moveLeft: true, list: React.createElement(React.Fragment, null,
21
- supplements.map((file, index) => (React.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
27
+ getSupplements(getFiles, getDoc, groupFiles).map((file, index) => (React.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
22
28
  getFileIcon(file.name),
23
29
  React.createElement(ListItemText, null, file.name)))),
24
- otherFiles.map((file, index) => (React.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
30
+ getOtherFiles(getFiles, getDoc, groupFiles).map((file, index) => (React.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
25
31
  getFileIcon(file.name),
26
32
  React.createElement(ListItemText, null, file.name)))),
27
33
  React.createElement(UploadButton, { onClick: onUpload, disabled: !showUpload },
@@ -53,7 +53,7 @@ export default (props) => {
53
53
  trackChangesPlugin({
54
54
  userID: props.userID,
55
55
  debug: props.debug,
56
- initialStatus: props.isViewingMode
56
+ initialStatus: props.isViewingMode || props.isComparingMode
57
57
  ? TrackChangesStatus.viewSnapshots
58
58
  : props.getCapabilities().editWithoutTracking
59
59
  ? TrackChangesStatus.disabled
@@ -10,6 +10,19 @@ const figureTypes = [
10
10
  schema.nodes.image_element,
11
11
  schema.nodes.hero_image,
12
12
  ];
13
+ export function memoGroupFiles() {
14
+ let prevFiles = [];
15
+ let prevDoc = undefined;
16
+ let result;
17
+ return function (doc, files) {
18
+ if (result && prevDoc === doc && prevFiles === files) {
19
+ return result;
20
+ }
21
+ prevDoc = doc;
22
+ prevFiles = files;
23
+ return groupFiles(doc, files);
24
+ };
25
+ }
13
26
  export const groupFiles = (doc, files) => {
14
27
  const fileMap = new Map(files.map((f) => [f.id, f]));
15
28
  const figures = [];
@@ -58,5 +58,5 @@ export const bibliographyItemTypes = [
58
58
  ['standard', 'Standard'],
59
59
  ['dataset', 'Dataset'],
60
60
  ['preprint', 'Preprint'],
61
- ['literal', 'Literal'],
61
+ ['literal', 'Unstructured'],
62
62
  ];
@@ -28,7 +28,14 @@ export const useEditor = (externalProps) => {
28
28
  const [state, setState] = useState(() => createEditorState(props));
29
29
  const location = useLocation();
30
30
  const { collabProvider } = props;
31
- if (collabProvider) {
31
+ useEffect(() => {
32
+ if (view.current && props.isComparingMode) {
33
+ const newState = createEditorState(props);
34
+ setState(newState);
35
+ view.current.updateState(newState);
36
+ }
37
+ }, [props.doc, props.isComparingMode]);
38
+ if (collabProvider && !props.isComparingMode) {
32
39
  collabProvider.onNewSteps(async () => {
33
40
  if (state && view.current) {
34
41
  const localVersion = getVersion(view.current.state);
@@ -54,7 +61,9 @@ export const useEditor = (externalProps) => {
54
61
  view.current.updateState(nextState);
55
62
  const trackState = trackChangesPluginKey.getState(view.current.state);
56
63
  if (collabProvider &&
57
- (!trackState || trackState.status !== TrackChangesStatus.viewSnapshots)) {
64
+ (!trackState ||
65
+ trackState.status !== TrackChangesStatus.viewSnapshots) &&
66
+ !props.isComparingMode) {
58
67
  const sendable = sendableSteps(nextState);
59
68
  if (sendable) {
60
69
  collabProvider.sendSteps(sendable.version, sendable.steps, sendable.clientID, false);
@@ -1,2 +1,2 @@
1
- export const VERSION = '3.2.4';
1
+ export const VERSION = '3.2.6';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -168,8 +168,28 @@ export class BibliographyElementBlockView extends BlockView {
168
168
  for (let i = 0; i < bibliography.length; i++) {
169
169
  const id = meta.entry_ids[i][0];
170
170
  const fragment = bibliography[i];
171
- const element = sanitize(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${fragment}</div></div>`).firstElementChild;
172
171
  const node = nodes.get(id);
172
+ const isUnstructured = node.attrs.type === 'literal';
173
+ const tempDiv = document.createElement('div');
174
+ tempDiv.innerHTML = fragment;
175
+ if (isUnstructured) {
176
+ const cslLeftMarginDiv = tempDiv.querySelector('.csl-left-margin');
177
+ let cslRightInlineDiv = tempDiv.querySelector('.csl-right-inline');
178
+ const cslEntry = tempDiv.querySelector('.csl-entry');
179
+ if (cslRightInlineDiv) {
180
+ cslRightInlineDiv.textContent = node.attrs.literal ?? '';
181
+ }
182
+ else if (cslLeftMarginDiv) {
183
+ cslRightInlineDiv = document.createElement('div');
184
+ cslRightInlineDiv.classList.add('csl-right-inline');
185
+ cslRightInlineDiv.textContent = node.attrs.literal ?? '';
186
+ cslLeftMarginDiv.after(cslRightInlineDiv);
187
+ }
188
+ else if (cslEntry) {
189
+ cslEntry.textContent = node.attrs.literal ?? '';
190
+ }
191
+ }
192
+ const element = sanitize(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${tempDiv.innerHTML}</div></div>`).firstElementChild;
173
193
  const comment = createCommentMarker('div', id);
174
194
  element.prepend(comment);
175
195
  addTrackChangesAttributes(node.attrs, element);
@@ -38,7 +38,11 @@ export class CitationView extends BaseNodeView {
38
38
  }
39
39
  const id = this.node.attrs.id;
40
40
  const text = bib.renderedCitations.get(id);
41
- const fragment = sanitize(text && text !== '[NO_PRINTED_FORM]' ? text : ' ', {
41
+ const fragment = sanitize(text === '(n.d.)'
42
+ ? 'Missing citation data'
43
+ : text && text !== '[NO_PRINTED_FORM]'
44
+ ? text
45
+ : ' ', {
42
46
  ALLOWED_TAGS: ['i', 'b', 'span', 'sup', 'sub', '#text'],
43
47
  });
44
48
  this.dom.innerHTML = '';
@@ -128,10 +128,9 @@ export class ContributorsView extends BlockView {
128
128
  action: () => this.handleEdit(''),
129
129
  icon: 'Edit',
130
130
  });
131
- this.contextMenu = ReactSubView(this.props, ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu']);
132
- return this.contextMenu;
133
131
  }
134
- return undefined;
132
+ this.contextMenu = ReactSubView(this.props, ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu']);
133
+ return this.contextMenu;
135
134
  };
136
135
  this.actionGutterButtons = () => {
137
136
  const contextMenu = this.authorContextMenu();
@@ -20,7 +20,6 @@ import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
20
20
  import { createElement } from 'react';
21
21
  import { renderToStaticMarkup } from 'react-dom/server';
22
22
  import { FigureOptions, } from '../components/views/FigureDropdown';
23
- import { groupFiles } from '../lib/files';
24
23
  import { isDeleted } from '../lib/track-changes-utils';
25
24
  import { updateNodeAttrs } from '../lib/view';
26
25
  import { createEditableNodeView } from './creators';
@@ -289,11 +288,10 @@ export class FigureEditableView extends FigureView {
289
288
  }
290
289
  this.reactTools?.remove();
291
290
  if (this.props.dispatch && this.props.theme) {
292
- const files = this.props.getFiles();
293
- const doc = this.view.state.doc;
294
291
  const componentProps = {
295
292
  can,
296
- files: groupFiles(doc, files),
293
+ getDoc: () => this.view.state.doc,
294
+ getFiles: this.props.getFiles,
297
295
  onDownload: handleDownload,
298
296
  onUpload: handleUpload,
299
297
  onDetach: handleDetach,
@@ -1,15 +1,17 @@
1
1
  import { Capabilities } from '@manuscripts/style-guide';
2
+ import { Node as ManuscriptNode } from 'prosemirror-model';
2
3
  import React from 'react';
3
- import { FileAttachment, ManuscriptFiles } from '../../lib/files';
4
+ import { FileAttachment } from '../../lib/files';
4
5
  export interface FigureDropdownProps {
5
6
  can: Capabilities;
6
- files: ManuscriptFiles;
7
+ getFiles: () => FileAttachment[];
7
8
  }
8
9
  export interface FigureOptionsProps extends FigureDropdownProps {
9
10
  onDownload?: () => void;
10
11
  onUpload?: () => void;
11
12
  onDetach?: () => void;
12
13
  onReplace?: (file: FileAttachment) => void;
14
+ getDoc: () => ManuscriptNode;
13
15
  onDelete?: () => void;
14
16
  }
15
17
  export interface FigureElementOptionsProps extends FigureDropdownProps {
@@ -49,6 +49,7 @@ export interface EditorProps {
49
49
  collabProvider?: CollabProvider;
50
50
  navigate: NavigateFunction;
51
51
  location: Location;
52
+ isComparingMode?: boolean;
52
53
  dispatch?: Dispatch;
53
54
  onEditorClick: (pos: number, node: ManuscriptNode, nodePos: number, event: MouseEvent) => void;
54
55
  lockBody: boolean;
@@ -28,4 +28,5 @@ export type FileManagement = {
28
28
  download: Download;
29
29
  previewLink: PreviewLink;
30
30
  };
31
+ export declare function memoGroupFiles(): (doc: ManuscriptNode, files: FileAttachment[]) => ManuscriptFiles;
31
32
  export declare const groupFiles: (doc: ManuscriptNode, files: FileAttachment[]) => ManuscriptFiles;
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "3.2.4";
1
+ export declare const VERSION = "3.2.6";
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.2.4",
4
+ "version": "3.2.6",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -40,7 +40,7 @@
40
40
  "@manuscripts/json-schema": "2.2.12",
41
41
  "@manuscripts/style-guide": "3.1.0",
42
42
  "@manuscripts/track-changes-plugin": "2.0.1",
43
- "@manuscripts/transform": "4.2.0",
43
+ "@manuscripts/transform": "4.2.1",
44
44
  "@popperjs/core": "2.11.8",
45
45
  "citeproc": "2.4.63",
46
46
  "codemirror": "5.65.19",
@@ -1053,6 +1053,19 @@ figure.block:has(.equation.selected-suggestion) {
1053
1053
  border-color: var(--updated-border-color);
1054
1054
  }
1055
1055
 
1056
+ /* Needed for the snapshot comparison */
1057
+ .tracking-visible .block-list [data-track-op="insert"][data-track-status="pending"] {
1058
+ background: var(--inserted-pending-bg-color);
1059
+ color: var(--inserted-pending-color);
1060
+ text-decoration: underline;
1061
+ }
1062
+ /* Needed for the snapshot comparison */
1063
+ .tracking-visible .block-list [data-track-op="delete"][data-track-status="pending"] {
1064
+ background: var(--deleted-pending-bg-color);
1065
+ color: var(--deleted-color);
1066
+ text-decoration: line-through;
1067
+ }
1068
+
1056
1069
  .selected-suggestion.contributor,
1057
1070
  .selected-suggestion.affiliation {
1058
1071
  text-decoration: none !important;