@manuscripts/body-editor 2.0.46-LEAN-3883.1 → 2.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/cjs/commands.js +12 -20
  2. package/dist/cjs/components/views/FootnotesSelector.js +4 -2
  3. package/dist/cjs/keys/misc.js +0 -1
  4. package/dist/cjs/lib/track-changes-utils.js +14 -46
  5. package/dist/cjs/plugins/footnotes/index.js +27 -129
  6. package/dist/cjs/plugins/footnotes/widgets.js +131 -0
  7. package/dist/cjs/plugins/{section_title/index.js → section_title.js} +1 -18
  8. package/dist/cjs/versions.js +1 -1
  9. package/dist/cjs/views/footnote.js +1 -0
  10. package/dist/cjs/views/inline_footnote.js +13 -7
  11. package/dist/es/commands.js +10 -17
  12. package/dist/es/components/views/FootnotesSelector.js +4 -2
  13. package/dist/es/keys/misc.js +2 -3
  14. package/dist/es/lib/track-changes-utils.js +13 -42
  15. package/dist/es/plugins/footnotes/index.js +23 -121
  16. package/dist/es/plugins/footnotes/widgets.js +122 -0
  17. package/dist/es/plugins/{section_title/index.js → section_title.js} +1 -18
  18. package/dist/es/versions.js +1 -1
  19. package/dist/es/views/footnote.js +1 -0
  20. package/dist/es/views/inline_footnote.js +14 -8
  21. package/dist/types/commands.d.ts +0 -1
  22. package/dist/types/lib/track-changes-utils.d.ts +1 -4
  23. package/dist/types/plugins/footnotes/index.d.ts +0 -1
  24. package/dist/types/plugins/footnotes/widgets.d.ts +22 -0
  25. package/dist/types/versions.d.ts +1 -1
  26. package/dist/types/views/inline_footnote.d.ts +2 -6
  27. package/package.json +3 -3
  28. package/styles/AdvancedEditor.css +43 -62
  29. package/dist/cjs/lib/section-titles.js +0 -35
  30. package/dist/cjs/plugins/section_title/autocompletion.js +0 -45
  31. package/dist/es/lib/section-titles.js +0 -32
  32. package/dist/es/plugins/section_title/autocompletion.js +0 -40
  33. package/dist/types/lib/section-titles.d.ts +0 -17
  34. package/dist/types/plugins/section_title/autocompletion.d.ts +0 -10
  35. /package/dist/types/plugins/{section_title/index.d.ts → section_title.d.ts} +0 -0
@@ -88,12 +88,18 @@ class InlineFootnoteView extends base_node_view_1.BaseNodeView {
88
88
  const fnState = footnotes_2.footnotesKey.getState(this.view.state);
89
89
  if (fnState) {
90
90
  this.activateModal({
91
- notes: Array.from(fnState.unusedFootnotes.values()).map((n) => ({
92
- node: n[0],
93
- })),
91
+ notes: Array.from(fnState.unusedFootnotes.values()).reduce((acc, n) => {
92
+ const node = n[0];
93
+ if (!(0, track_changes_utils_1.isDeleted)(node) && !(0, track_changes_utils_1.isRejectedInsert)(node)) {
94
+ acc.push({
95
+ node,
96
+ });
97
+ }
98
+ return acc;
99
+ }, []),
94
100
  onCancel: () => {
95
101
  const { tr } = this.view.state;
96
- if (!this.node.attrs.rids.length) {
102
+ if (!(0, track_changes_utils_1.getActualAttrs)(this.node).rids.length) {
97
103
  this.view.dispatch(tr.delete(this.getPos(), this.getPos() + this.node.nodeSize));
98
104
  }
99
105
  this.destroy();
@@ -120,7 +126,7 @@ class InlineFootnoteView extends base_node_view_1.BaseNodeView {
120
126
  this.dom.setAttribute('contents', attrs.contents);
121
127
  this.dom.className = [
122
128
  'footnote',
123
- ...(0, track_changes_utils_1.getChangeClasses)(attrs.dataTracked),
129
+ ...(0, track_changes_utils_1.getChangeClasses)(this.node.attrs.dataTracked),
124
130
  ].join(' ');
125
131
  if (this.isSelected() &&
126
132
  (!attrs.rids || !attrs.rids.length) &&
@@ -170,8 +176,8 @@ class InlineFootnoteView extends base_node_view_1.BaseNodeView {
170
176
  };
171
177
  this.onInsert = (notes) => {
172
178
  if (notes.length) {
173
- const contents = this.node.attrs.contents
174
- .split(',')
179
+ const contents = (0, track_changes_utils_1.getActualAttrs)(this.node)
180
+ .contents.split(',')
175
181
  .map((n) => parseInt(n));
176
182
  const rids = notes.map((note) => note.node.attrs.id);
177
183
  const { tr } = this.view.state;
@@ -26,13 +26,11 @@ import { getCommentKey, getCommentRange } from './lib/comments';
26
26
  import { findBackmatter, findBibliographySection, findBody, insertSupplementsNode, } from './lib/doc';
27
27
  import { getNewFootnotePos } from './lib/footnotes';
28
28
  import { findWordBoundaries, isNodeOfType, nearestAncestor, } from './lib/helpers';
29
- import { sectionTitles } from './lib/section-titles';
30
29
  import { isDeleted, isRejectedInsert } from './lib/track-changes-utils';
31
30
  import { findParentNodeWithId, getChildOfType, getMatchingChild, } from './lib/utils';
32
31
  import { setCommentSelection } from './plugins/comments';
33
32
  import { getEditorProps } from './plugins/editor-props';
34
33
  import { footnotesKey } from './plugins/footnotes';
35
- import { checkForCompletion } from './plugins/section_title/autocompletion';
36
34
  export const markActive = (type) => (state) => {
37
35
  const { from, $from, to, empty } = state.selection;
38
36
  return empty
@@ -456,6 +454,16 @@ export const insertSection = (subsection = false) => (state, dispatch, view) =>
456
454
  }
457
455
  return true;
458
456
  };
457
+ const sectionTitles = new Map([
458
+ ['MPSectionCategory:acknowledgement', 'Acknowledgments'],
459
+ ['MPSectionCategory:availability', 'Availability'],
460
+ ['MPSectionCategory:competing-interests', 'COI Statement'],
461
+ ['MPSectionCategory:con', 'Contributed-by information'],
462
+ ['MPSectionCategory:ethics-statement', 'Ethics Statement'],
463
+ ['MPSectionCategory:financial-disclosure', 'Financial Disclosure'],
464
+ ['MPSectionCategory:supplementary-material', 'Supplementary Material'],
465
+ ['MPSectionCategory:supported-by', 'Supported By'],
466
+ ]);
459
467
  export const insertBackMatterSection = (category) => (state, dispatch, view) => {
460
468
  const backmatter = findBackmatter(state.doc);
461
469
  const sections = findChildrenByType(backmatter.node, schema.nodes.section);
@@ -1083,18 +1091,3 @@ export function mergeCellsWithSpace(state, dispatch) {
1083
1091
  }
1084
1092
  return true;
1085
1093
  }
1086
- export const autoComplete = (state, dispatch) => {
1087
- const complete = checkForCompletion(state);
1088
- if (complete) {
1089
- const tr = state.tr.insertText(complete.suggestion, state.selection.from);
1090
- const inserted = complete.title.substring(0, complete.title.length - complete.suggestion.length);
1091
- console.log(inserted);
1092
- console.log(complete);
1093
- if (inserted) {
1094
- tr.replaceWith(state.selection.from - inserted.length, state.selection.from, schema.text(inserted));
1095
- }
1096
- dispatch && dispatch(tr);
1097
- return true;
1098
- }
1099
- return false;
1100
- };
@@ -16,6 +16,7 @@
16
16
  import { AddedIcon, AddIcon, AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, } from '@manuscripts/style-guide';
17
17
  import React, { useState } from 'react';
18
18
  import styled from 'styled-components';
19
+ import { getActualAttrs } from '../../lib/track-changes-utils';
19
20
  const NotesContainer = styled.div `
20
21
  height: 90vh;
21
22
  max-height: 400px;
@@ -50,7 +51,7 @@ const AddNewFootnote = styled(ButtonGroup) `
50
51
  export const FootnotesSelector = ({ notes, inlineFootnote, onAdd, onInsert, onCancel, addNewLabel }) => {
51
52
  let selectedNotesMap;
52
53
  if (inlineFootnote) {
53
- const rids = inlineFootnote.attrs.rids;
54
+ const rids = getActualAttrs(inlineFootnote).rids;
54
55
  const selectedNotes = notes.filter(({ node }) => rids.includes(node.attrs.id));
55
56
  selectedNotesMap = new Map(selectedNotes.map(({ node }) => [node.attrs.id, node]));
56
57
  }
@@ -88,7 +89,8 @@ const FootnotesList = ({ notes, isSelected, onSelect, inlineFootnote }) => {
88
89
  const selectedNotes = [];
89
90
  const remainingNotes = [];
90
91
  notes.forEach((note) => {
91
- const isNoteSelected = inlineFootnote && inlineFootnote.attrs.rids.includes(note.node.attrs.id);
92
+ const isNoteSelected = inlineFootnote &&
93
+ getActualAttrs(inlineFootnote).rids.includes(note.node.attrs.id);
92
94
  if (isNoteSelected) {
93
95
  selectedNotes.push(note);
94
96
  }
@@ -14,11 +14,11 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { schema } from '@manuscripts/transform';
17
- import { chainCommands, createParagraphNear, exitCode, joinDown, joinUp, lift, liftEmptyBlock, newlineInCode, splitBlock, toggleMark, wrapIn, } from 'prosemirror-commands';
17
+ import { chainCommands, exitCode, joinDown, joinUp, lift, toggleMark, wrapIn, } from 'prosemirror-commands';
18
18
  import { redo, undo } from 'prosemirror-history';
19
19
  import { undoInputRule } from 'prosemirror-inputrules';
20
20
  import { goToNextCell } from 'prosemirror-tables';
21
- import { autoComplete, ignoreAtomBlockNodeBackward, ignoreAtomBlockNodeForward, ignoreMetaNodeBackspaceCommand, insertBlock, insertBreak, insertCrossReference, insertInlineCitation, insertInlineEquation, insertSection, selectAllIsolating, } from '../commands';
21
+ import { ignoreAtomBlockNodeBackward, ignoreAtomBlockNodeForward, ignoreMetaNodeBackspaceCommand, insertBlock, insertBreak, insertCrossReference, insertInlineCitation, insertInlineEquation, insertSection, selectAllIsolating, } from '../commands';
22
22
  const customKeymap = {
23
23
  Backspace: chainCommands(undoInputRule, ignoreAtomBlockNodeBackward, ignoreMetaNodeBackspaceCommand),
24
24
  Delete: ignoreAtomBlockNodeForward,
@@ -37,7 +37,6 @@ const customKeymap = {
37
37
  'Mod-Alt-=': toggleMark(schema.marks.superscript),
38
38
  'Mod-Alt--': toggleMark(schema.marks.subscript),
39
39
  'Ctrl->': wrapIn(schema.nodes.blockquote),
40
- Enter: chainCommands(autoComplete, newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock),
41
40
  'Shift-Mod-Enter': insertSection(true),
42
41
  'Mod-Enter': chainCommands(exitCode, insertSection()),
43
42
  'Shift-Enter': chainCommands(exitCode, insertBreak),
@@ -14,7 +14,6 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { EditAttrsTrackingIcon } from '@manuscripts/style-guide';
17
- import { schema } from '@manuscripts/transform';
18
17
  import { createElement } from 'react';
19
18
  import { renderToStaticMarkup } from 'react-dom/server';
20
19
  export function isRejectedInsert(node) {
@@ -75,11 +74,20 @@ export function isTracked(node) {
75
74
  return false;
76
75
  }
77
76
  export function getActualAttrs(node) {
77
+ var _a;
78
78
  const attrs = node.attrs;
79
- if (attrs.dataTracked &&
80
- attrs.dataTracked[0].status === 'rejected' &&
81
- attrs.dataTracked[0].operation === 'set_attrs') {
82
- return attrs.dataTracked[0].oldAttrs;
79
+ if ((_a = attrs.dataTracked) === null || _a === void 0 ? void 0 : _a.length) {
80
+ const changes = attrs.dataTracked.filter((c) => c.operation === 'set_attrs');
81
+ const hasPendingAttrs = changes.some((c) => c.status === 'pending');
82
+ if (hasPendingAttrs) {
83
+ return attrs;
84
+ }
85
+ const rejected = changes
86
+ .filter((c) => c.status === 'rejected')
87
+ .sort((a, b) => b.statusUpdateAt - a.statusUpdateAt)[0];
88
+ if (rejected && rejected.status === 'rejected') {
89
+ return rejected.oldAttrs;
90
+ }
83
91
  }
84
92
  return attrs;
85
93
  }
@@ -93,43 +101,6 @@ export const getAttrsTrackingButton = (changeID) => {
93
101
  export function isHidden(node) {
94
102
  return isDeleted(node) || isRejectedInsert(node);
95
103
  }
96
- export function isDeletedText(node) {
97
- var _a, _b, _c, _d;
98
- if (node.type === schema.nodes.text && node.marks.length) {
99
- const deleteMark = node.marks.find((mark) => mark.type === schema.marks.tracked_delete);
100
- if (deleteMark &&
101
- ((_b = (_a = deleteMark.attrs) === null || _a === void 0 ? void 0 : _a.dataTracked) === null || _b === void 0 ? void 0 : _b.status) &&
102
- ['pending', 'approved'].includes((_d = (_c = deleteMark.attrs) === null || _c === void 0 ? void 0 : _c.dataTracked) === null || _d === void 0 ? void 0 : _d.status)) {
103
- return true;
104
- }
105
- }
106
- return false;
107
- }
108
- export function isRejectedText(node) {
109
- var _a, _b;
110
- if (node.type === schema.nodes.text) {
111
- const insertMark = node.marks.find((mark) => mark.type === schema.marks.tracked_insert);
112
- if (insertMark && ((_b = (_a = insertMark.attrs) === null || _a === void 0 ? void 0 : _a.dataTracked) === null || _b === void 0 ? void 0 : _b.status) === 'rejected') {
113
- return true;
114
- }
115
- }
116
- return false;
117
- }
118
- export function getActualTextContent(fragment) {
119
- let finalContent = '';
120
- function getContent(fragment) {
121
- fragment.forEach((node) => {
122
- if (node.type !== schema.nodes.text) {
123
- finalContent += getContent(node.content);
124
- }
125
- if (!isDeletedText(node) && !isRejectedText(node)) {
126
- finalContent += node.textContent;
127
- }
128
- });
129
- }
130
- getContent(fragment);
131
- return finalContent;
132
- }
133
104
  export function sanitizeAttrsChange(newAttr, currentAttrs) {
134
105
  return Object.keys(newAttr).reduce((acc, attr) => {
135
106
  const key = attr;
@@ -13,117 +13,18 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { AlertIcon, DeleteIcon } from '@manuscripts/style-guide';
17
16
  import { skipTracking } from '@manuscripts/track-changes-plugin';
18
17
  import { isFootnoteNode, isFootnotesElementNode, isFootnotesSectionNode, isInlineFootnoteNode, schema, } from '@manuscripts/transform';
19
18
  import { isEqual } from 'lodash';
20
- import { NodeSelection, Plugin, PluginKey, TextSelection, } from 'prosemirror-state';
19
+ import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
21
20
  import { findParentNodeClosestToPos, findParentNodeOfType, } from 'prosemirror-utils';
22
21
  import { Decoration, DecorationSet } from 'prosemirror-view';
23
- import { createElement } from 'react';
24
- import { renderToStaticMarkup } from 'react-dom/server';
25
22
  import { isTextSelection } from '../../commands';
26
- import { DeleteFootnoteDialog, } from '../../components/views/DeleteFootnoteDialog';
27
- import { findTableInlineFootnoteIds, getAlphaOrderIndices, getInlineFootnotes, } from '../../lib/footnotes';
28
- import { getChildOfType } from '../../lib/utils';
29
- import ReactSubView from '../../views/ReactSubView';
23
+ import { findTableInlineFootnoteIds, getAlphaOrderIndices, } from '../../lib/footnotes';
30
24
  import { placeholderWidget } from '../placeholder';
25
+ import { getActualAttrs } from '../../lib/track-changes-utils';
26
+ import { deleteFootnoteWidget, labelWidget, uncitedFootnoteWidget, } from './widgets';
31
27
  export const footnotesKey = new PluginKey('footnotes');
32
- const scrollToInlineFootnote = (rid, view) => {
33
- view.state.doc.descendants((node, pos) => {
34
- const footnote = node;
35
- if (isInlineFootnoteNode(node) && footnote.attrs.rids.includes(rid)) {
36
- const selection = NodeSelection.create(view.state.doc, pos);
37
- view.dispatch(view.state.tr.setSelection(selection).scrollIntoView());
38
- }
39
- });
40
- };
41
- const labelWidget = (label, id) => (view) => {
42
- const element = document.createElement('span');
43
- element.className = 'footnote-label';
44
- element.textContent = label;
45
- element.addEventListener('mousedown', () => {
46
- scrollToInlineFootnote(id, view);
47
- });
48
- return element;
49
- };
50
- export const uncitedFootnoteWidget = () => () => {
51
- const element = document.createElement('span');
52
- element.className = 'uncited-footnote';
53
- element.innerHTML = renderToStaticMarkup(createElement(AlertIcon));
54
- return element;
55
- };
56
- const deleteFootnoteWidget = (node, props, id, tableElement, tableElementFooter) => (view, getPos) => {
57
- const deleteBtn = document.createElement('span');
58
- deleteBtn.className = 'delete-icon';
59
- deleteBtn.innerHTML = renderToStaticMarkup(createElement(DeleteIcon));
60
- const parentType = tableElement ? 'table ' : '';
61
- const footnote = {
62
- type: node.type === schema.nodes.footnote
63
- ? `${parentType}footnote`
64
- : 'table general note',
65
- message: node.type === schema.nodes.footnote
66
- ? `This action will entirely remove the ${parentType}footnote from the list because it will no longer be used.`
67
- : 'This action will entirely remove the table general note.',
68
- };
69
- deleteBtn.addEventListener('mousedown', () => {
70
- const handleDelete = () => {
71
- const tr = view.state.tr;
72
- const pos = getPos();
73
- if (node.type === schema.nodes.general_table_footnote && pos) {
74
- if (tableElementFooter &&
75
- !getChildOfType(tableElementFooter.node, schema.nodes.footnotes_element, true) &&
76
- tableElementFooter.pos) {
77
- tr.delete(tableElementFooter.pos - 1, tableElementFooter.pos + tableElementFooter.node.nodeSize);
78
- }
79
- else {
80
- tr.delete(pos - 1, pos + node.nodeSize + 1);
81
- }
82
- }
83
- if (node.type === schema.nodes.footnote && pos) {
84
- const targetNode = tableElement ? tableElement.node : view.state.doc;
85
- const inlineFootnotes = getInlineFootnotes(id, targetNode);
86
- const footnotesElement = findParentNodeClosestToPos(tr.doc.resolve(pos), (node) => node.type === schema.nodes.footnotes_element);
87
- if ((footnotesElement === null || footnotesElement === void 0 ? void 0 : footnotesElement.node.childCount) === 1 &&
88
- (tableElementFooter === null || tableElementFooter === void 0 ? void 0 : tableElementFooter.node.childCount) === 1) {
89
- const { pos: fnPos, node: fnNode } = tableElementFooter;
90
- tr.delete(fnPos, fnPos + fnNode.nodeSize + 1);
91
- }
92
- else if ((footnotesElement === null || footnotesElement === void 0 ? void 0 : footnotesElement.node.childCount) === 1) {
93
- const { pos: fnPos, node: fnNode } = footnotesElement;
94
- tr.delete(fnPos, fnPos + fnNode.nodeSize + 1);
95
- }
96
- else {
97
- const footnote = findParentNodeClosestToPos(tr.doc.resolve(pos), (node) => node.type === schema.nodes.footnote);
98
- if (footnote) {
99
- const { pos: fnPos, node: fnNode } = footnote;
100
- tr.delete(fnPos, fnPos + fnNode.nodeSize + 1);
101
- }
102
- }
103
- if (inlineFootnotes) {
104
- inlineFootnotes.forEach((footnote) => {
105
- const pos = footnote.pos + (tableElement ? tableElement.pos + 1 : 0);
106
- if (footnote.node.attrs.rids.length > 1) {
107
- const updatedRids = footnote.node.attrs.rids.filter((rid) => rid !== id);
108
- tr.setNodeMarkup(tr.mapping.map(pos), undefined, Object.assign(Object.assign({}, node.attrs), { rids: updatedRids }));
109
- }
110
- else {
111
- tr.delete(tr.mapping.map(pos), tr.mapping.map(pos + footnote.node.nodeSize));
112
- }
113
- });
114
- }
115
- }
116
- view.dispatch(tr);
117
- };
118
- const componentProps = {
119
- footnoteType: footnote.type,
120
- footnoteMessage: footnote.message,
121
- handleDelete: handleDelete,
122
- };
123
- ReactSubView(Object.assign(Object.assign({}, props), { dispatch: view.dispatch }), DeleteFootnoteDialog, componentProps, node, () => getPos(), view);
124
- });
125
- return deleteBtn;
126
- };
127
28
  export const buildPluginState = (doc) => {
128
29
  const inlineFootnotes = [];
129
30
  const footnotes = new Map();
@@ -150,25 +51,25 @@ export const buildPluginState = (doc) => {
150
51
  const labels = new Map();
151
52
  inlineFootnotes.sort((a, b) => a[1] - b[1]);
152
53
  inlineFootnotes.forEach(([node]) => {
153
- node.attrs.rids.forEach((rid) => {
54
+ getActualAttrs(node).rids.forEach((rid) => {
154
55
  labels.set(rid, getAlphaOrderIndices(index++));
155
56
  });
156
57
  });
157
58
  const footnotesReordered = [];
158
- const footnotesRest = new Map(footnotes);
59
+ const unusedFootnotes = new Map(footnotes);
159
60
  inlineFootnotes.forEach(([node]) => {
160
61
  const footnote = node;
161
- footnote.attrs.rids.forEach((rid) => {
162
- const currentfNode = footnotesRest.get(rid);
163
- if (currentfNode) {
164
- footnotesReordered.push(currentfNode[0]);
165
- footnotesRest.delete(rid);
62
+ getActualAttrs(footnote).rids.forEach((rid) => {
63
+ const currentFnNode = unusedFootnotes.get(rid);
64
+ if (currentFnNode) {
65
+ footnotesReordered.push(currentFnNode[0]);
66
+ unusedFootnotes.delete(rid);
166
67
  }
167
68
  });
168
69
  });
169
70
  return {
170
71
  inlineFootnotes,
171
- unusedFootnotes: footnotesRest,
72
+ unusedFootnotes,
172
73
  footnotes,
173
74
  footnoteElement,
174
75
  labels,
@@ -192,8 +93,8 @@ export default (props) => {
192
93
  appendTransaction(transactions, oldState, newState) {
193
94
  const { inlineFootnotes: oldInlineFootnoteNodes } = footnotesKey.getState(oldState);
194
95
  const { inlineFootnotes: inlineFootnoteNodes, footnotes, labels, footnoteElement, unusedFootnotes, } = footnotesKey.getState(newState);
195
- const prevIds = oldInlineFootnoteNodes.map(([node]) => node.attrs.rids);
196
- const newIds = inlineFootnoteNodes.map(([node]) => node.attrs.rids);
96
+ const prevIds = oldInlineFootnoteNodes.map(([node]) => getActualAttrs(node).rids);
97
+ const newIds = inlineFootnoteNodes.map(([node]) => getActualAttrs(node).rids);
197
98
  const initTransaction = transactions.find((t) => t.getMeta('INIT'));
198
99
  if (!footnoteElement || (!initTransaction && isEqual(prevIds, newIds))) {
199
100
  return null;
@@ -202,23 +103,24 @@ export default (props) => {
202
103
  const footnotesReordered = [];
203
104
  inlineFootnoteNodes.forEach(([node, pos]) => {
204
105
  const footnote = node;
205
- const contents = footnote.attrs.rids
106
+ const attrs = getActualAttrs(footnote);
107
+ const contents = attrs.rids
206
108
  .map((rid) => {
207
- const currentfNode = footnotes.get(rid);
208
- if (currentfNode) {
209
- footnotesReordered.push(currentfNode[0]);
109
+ const currentFnNode = footnotes.get(rid);
110
+ if (currentFnNode) {
111
+ footnotesReordered.push(currentFnNode[0]);
210
112
  }
211
113
  return labels.get(rid);
212
114
  })
213
115
  .join('');
214
- if (footnote.attrs.contents !== contents) {
116
+ if (attrs.contents !== contents) {
215
117
  tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, footnote.attrs), { rids: footnote.attrs.rids, contents }));
216
118
  }
217
119
  });
218
120
  unusedFootnotes.forEach(([node]) => footnotesReordered.push(node));
219
- const newFElement = schema.nodes.footnotes_element.create(footnoteElement[0].attrs, footnotesReordered);
220
- if (newFElement && footnotes.size > 0) {
221
- tr.replaceWith(footnoteElement[1], footnoteElement[1] + footnoteElement[0].nodeSize, newFElement);
121
+ const newFnElement = schema.nodes.footnotes_element.create(footnoteElement[0].attrs, footnotesReordered);
122
+ if (newFnElement && footnotes.size > 0) {
123
+ tr.replaceWith(footnoteElement[1], footnoteElement[1] + footnoteElement[0].nodeSize, newFnElement);
222
124
  }
223
125
  const prevSelection = newState.selection;
224
126
  const selectedFootnote = findParentNodeClosestToPos(prevSelection.$anchor, (node) => isFootnoteNode(node));
@@ -0,0 +1,122 @@
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
+ import { AlertIcon, DeleteIcon } from '@manuscripts/style-guide';
17
+ import { isInlineFootnoteNode, schema, } from '@manuscripts/transform';
18
+ import { NodeSelection } from 'prosemirror-state';
19
+ import { findParentNodeClosestToPos } from 'prosemirror-utils';
20
+ import { createElement } from 'react';
21
+ import { renderToStaticMarkup } from 'react-dom/server';
22
+ import { DeleteFootnoteDialog, } from '../../components/views/DeleteFootnoteDialog';
23
+ import { getInlineFootnotes } from '../../lib/footnotes';
24
+ import { getChildOfType } from '../../lib/utils';
25
+ import ReactSubView from '../../views/ReactSubView';
26
+ import { getActualAttrs } from '../../lib/track-changes-utils';
27
+ export const deleteFootnoteWidget = (node, props, id, tableElement, tableElementFooter) => (view, getPos) => {
28
+ const deleteBtn = document.createElement('span');
29
+ deleteBtn.className = 'delete-icon';
30
+ deleteBtn.innerHTML = renderToStaticMarkup(createElement(DeleteIcon));
31
+ const parentType = tableElement ? 'table ' : '';
32
+ const footnote = {
33
+ type: node.type === schema.nodes.footnote
34
+ ? `${parentType}footnote`
35
+ : 'table general note',
36
+ message: node.type === schema.nodes.footnote
37
+ ? `This action will entirely remove the ${parentType}footnote from the list because it will no longer be used.`
38
+ : 'This action will entirely remove the table general note.',
39
+ };
40
+ deleteBtn.addEventListener('mousedown', () => {
41
+ const handleDelete = () => {
42
+ const tr = view.state.tr;
43
+ const pos = getPos();
44
+ if (node.type === schema.nodes.general_table_footnote && pos) {
45
+ if (tableElementFooter &&
46
+ !getChildOfType(tableElementFooter.node, schema.nodes.footnotes_element, true) &&
47
+ tableElementFooter.pos) {
48
+ tr.delete(tableElementFooter.pos - 1, tableElementFooter.pos + tableElementFooter.node.nodeSize);
49
+ }
50
+ else {
51
+ tr.delete(pos - 1, pos + node.nodeSize + 1);
52
+ }
53
+ }
54
+ if (node.type === schema.nodes.footnote && pos) {
55
+ const targetNode = tableElement ? tableElement.node : view.state.doc;
56
+ const inlineFootnotes = getInlineFootnotes(id, targetNode);
57
+ const footnotesElement = findParentNodeClosestToPos(tr.doc.resolve(pos), (node) => node.type === schema.nodes.footnotes_element);
58
+ if ((footnotesElement === null || footnotesElement === void 0 ? void 0 : footnotesElement.node.childCount) === 1 &&
59
+ (tableElementFooter === null || tableElementFooter === void 0 ? void 0 : tableElementFooter.node.childCount) === 1) {
60
+ const { pos: fnPos, node: fnNode } = tableElementFooter;
61
+ tr.delete(fnPos, fnPos + fnNode.nodeSize + 1);
62
+ }
63
+ else if ((footnotesElement === null || footnotesElement === void 0 ? void 0 : footnotesElement.node.childCount) === 1) {
64
+ const { pos: fnPos, node: fnNode } = footnotesElement;
65
+ tr.delete(fnPos, fnPos + fnNode.nodeSize + 1);
66
+ }
67
+ else {
68
+ const footnote = findParentNodeClosestToPos(tr.doc.resolve(pos), (node) => node.type === schema.nodes.footnote);
69
+ if (footnote) {
70
+ const { pos: fnPos, node: fnNode } = footnote;
71
+ tr.delete(fnPos, fnPos + fnNode.nodeSize + 1);
72
+ }
73
+ }
74
+ if (inlineFootnotes) {
75
+ inlineFootnotes.forEach((footnote) => {
76
+ const pos = footnote.pos + (tableElement ? tableElement.pos + 1 : 0);
77
+ if (footnote.node.attrs.rids.length > 1) {
78
+ const updatedRids = footnote.node.attrs.rids.filter((rid) => rid !== id);
79
+ tr.setNodeMarkup(tr.mapping.map(pos), undefined, Object.assign(Object.assign({}, node.attrs), { rids: updatedRids }));
80
+ }
81
+ else {
82
+ tr.delete(tr.mapping.map(pos), tr.mapping.map(pos + footnote.node.nodeSize));
83
+ }
84
+ });
85
+ }
86
+ }
87
+ view.dispatch(tr);
88
+ };
89
+ const componentProps = {
90
+ footnoteType: footnote.type,
91
+ footnoteMessage: footnote.message,
92
+ handleDelete: handleDelete,
93
+ };
94
+ ReactSubView(Object.assign(Object.assign({}, props), { dispatch: view.dispatch }), DeleteFootnoteDialog, componentProps, node, () => getPos(), view);
95
+ });
96
+ return deleteBtn;
97
+ };
98
+ const scrollToInlineFootnote = (rid, view) => {
99
+ view.state.doc.descendants((node, pos) => {
100
+ const footnote = node;
101
+ if (isInlineFootnoteNode(node) &&
102
+ getActualAttrs(footnote).rids.includes(rid)) {
103
+ const selection = NodeSelection.create(view.state.doc, pos);
104
+ view.dispatch(view.state.tr.setSelection(selection).scrollIntoView());
105
+ }
106
+ });
107
+ };
108
+ export const labelWidget = (label, id) => (view) => {
109
+ const element = document.createElement('span');
110
+ element.className = 'footnote-label';
111
+ element.textContent = label;
112
+ element.addEventListener('mousedown', () => {
113
+ scrollToInlineFootnote(id, view);
114
+ });
115
+ return element;
116
+ };
117
+ export const uncitedFootnoteWidget = () => () => {
118
+ const element = document.createElement('span');
119
+ element.className = 'uncited-footnote';
120
+ element.innerHTML = renderToStaticMarkup(createElement(AlertIcon));
121
+ return element;
122
+ };
@@ -1,9 +1,7 @@
1
1
  import { schema } from '@manuscripts/transform';
2
2
  import { Plugin, PluginKey } from 'prosemirror-state';
3
3
  import { findChildrenByType } from 'prosemirror-utils';
4
- import { Decoration, DecorationSet } from 'prosemirror-view';
5
- import { isRejectedInsert } from '../../lib/track-changes-utils';
6
- import { checkForCompletion } from './autocompletion';
4
+ import { isRejectedInsert } from '../lib/track-changes-utils';
7
5
  export const sectionTitleKey = new PluginKey('sectionNumbering');
8
6
  const calculateSectionLevels = (node, startPos, sectionNumberMap, numbering = [0]) => {
9
7
  node.forEach((childNode, offset) => {
@@ -34,21 +32,6 @@ const getPluginState = (doc) => {
34
32
  export default () => {
35
33
  return new Plugin({
36
34
  key: sectionTitleKey,
37
- props: {
38
- decorations(state) {
39
- const text = checkForCompletion(state);
40
- if (text) {
41
- const decoration = Decoration.widget(state.selection.from, () => {
42
- const node = document.createElement('span');
43
- node.classList.add('completion-bearer');
44
- node.dataset.suggest = text.suggestion;
45
- return node;
46
- });
47
- return DecorationSet.create(state.doc, [decoration]);
48
- }
49
- return DecorationSet.empty;
50
- },
51
- },
52
35
  state: {
53
36
  init: (_, state) => {
54
37
  return getPluginState(state.doc);
@@ -1,2 +1,2 @@
1
- export const VERSION = '2.0.46-LEAN-3883.1';
1
+ export const VERSION = '2.0.46';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -29,5 +29,6 @@ export const setTCClasses = (node, dom) => {
29
29
  const changeClasses = getChangeClasses([lastChange]);
30
30
  dom.classList.add(...changeClasses);
31
31
  }
32
+ dom.setAttribute('id', node.attrs.id);
32
33
  };
33
34
  export default createNodeOrElementView(FootnoteView, 'div', setTCClasses);
@@ -20,7 +20,7 @@ import { findChildrenByType, findParentNodeClosestToPos, } from 'prosemirror-uti
20
20
  import { createFootnote, insertFootnote, insertTableFootnote, } from '../commands';
21
21
  import { FootnotesSelector } from '../components/views/FootnotesSelector';
22
22
  import { buildTableFootnoteLabels } from '../lib/footnotes';
23
- import { getChangeClasses, isDeleted, isPendingInsert, isRejectedInsert, } from '../lib/track-changes-utils';
23
+ import { getActualAttrs, getChangeClasses, isDeleted, isPendingInsert, isRejectedInsert, } from '../lib/track-changes-utils';
24
24
  import { footnotesKey } from '../plugins/footnotes';
25
25
  import { BaseNodeView } from './base_node_view';
26
26
  import { createNodeView } from './creators';
@@ -82,12 +82,18 @@ export class InlineFootnoteView extends BaseNodeView {
82
82
  const fnState = footnotesKey.getState(this.view.state);
83
83
  if (fnState) {
84
84
  this.activateModal({
85
- notes: Array.from(fnState.unusedFootnotes.values()).map((n) => ({
86
- node: n[0],
87
- })),
85
+ notes: Array.from(fnState.unusedFootnotes.values()).reduce((acc, n) => {
86
+ const node = n[0];
87
+ if (!isDeleted(node) && !isRejectedInsert(node)) {
88
+ acc.push({
89
+ node,
90
+ });
91
+ }
92
+ return acc;
93
+ }, []),
88
94
  onCancel: () => {
89
95
  const { tr } = this.view.state;
90
- if (!this.node.attrs.rids.length) {
96
+ if (!getActualAttrs(this.node).rids.length) {
91
97
  this.view.dispatch(tr.delete(this.getPos(), this.getPos() + this.node.nodeSize));
92
98
  }
93
99
  this.destroy();
@@ -114,7 +120,7 @@ export class InlineFootnoteView extends BaseNodeView {
114
120
  this.dom.setAttribute('contents', attrs.contents);
115
121
  this.dom.className = [
116
122
  'footnote',
117
- ...getChangeClasses(attrs.dataTracked),
123
+ ...getChangeClasses(this.node.attrs.dataTracked),
118
124
  ].join(' ');
119
125
  if (this.isSelected() &&
120
126
  (!attrs.rids || !attrs.rids.length) &&
@@ -164,8 +170,8 @@ export class InlineFootnoteView extends BaseNodeView {
164
170
  };
165
171
  this.onInsert = (notes) => {
166
172
  if (notes.length) {
167
- const contents = this.node.attrs.contents
168
- .split(',')
173
+ const contents = getActualAttrs(this.node)
174
+ .contents.split(',')
169
175
  .map((n) => parseInt(n));
170
176
  const rids = notes.map((note) => note.node.attrs.id);
171
177
  const { tr } = this.view.state;
@@ -75,5 +75,4 @@ export declare const insertTableFootnote: (tableElementNode: ManuscriptNode, pos
75
75
  export declare const addRows: (direction: 'top' | 'bottom') => (state: EditorState, dispatch?: ((tr: Transaction) => void) | undefined) => boolean;
76
76
  export declare const addColumns: (direction: 'right' | 'left') => (state: EditorState, dispatch?: ((tr: Transaction) => void) | undefined) => boolean;
77
77
  export declare function mergeCellsWithSpace(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;
78
- export declare const autoComplete: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
79
78
  export {};