@manuscripts/body-editor 1.7.23 → 1.7.24-LEAN-3429-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,7 @@ const prosemirror_state_1 = require("prosemirror-state");
25
25
  const prosemirror_transform_1 = require("prosemirror-transform");
26
26
  const prosemirror_utils_1 = require("prosemirror-utils");
27
27
  const list_1 = require("./keys/list");
28
+ const footnotes_utils_1 = require("./lib/footnotes-utils");
28
29
  const helpers_1 = require("./lib/helpers");
29
30
  const track_changes_utils_1 = require("./lib/track-changes-utils");
30
31
  const utils_1 = require("./lib/utils");
@@ -726,36 +727,32 @@ const updateCommentAnnotationState = (state, dispatch) => {
726
727
  }
727
728
  };
728
729
  exports.updateCommentAnnotationState = updateCommentAnnotationState;
729
- const insertTableFootnote = (node, position, state, dispatch) => {
730
+ const insertTableFootnote = (node, position, view, tablesFootnoteLabels) => {
730
731
  var _a;
732
+ const { state, dispatch } = view;
731
733
  const footnote = state.schema.nodes.footnote.createAndFill({
732
734
  id: (0, transform_1.generateID)(json_schema_1.ObjectTypes.Footnote),
733
735
  kind: 'footnote',
734
736
  });
735
737
  const insertedAt = state.selection.to;
736
738
  const inlineFootnotes = (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.inline_footnote);
737
- const labels = inlineFootnotes.map((nodeWithPos) => nodeWithPos.node.attrs.contents);
738
- const inlineFootnoteNode = state.schema.nodes.inline_footnote.create({
739
- rids: [footnote.attrs.id],
740
- contents: labels.length ? Math.max(...labels) + 1 : 1,
741
- });
739
+ const footnoteIndex = inlineFootnotes.filter(({ pos }) => position + pos >= insertedAt).length - 1;
742
740
  const tr = state.tr;
743
- tr.insert(insertedAt, inlineFootnoteNode);
744
- let insertionPos;
745
- const footnotesElement = (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.footnotes_element).pop();
741
+ let insertionPos = position;
742
+ const footnotesElement = (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.footnotes_element)[0];
746
743
  if (footnotesElement &&
747
744
  !(0, track_changes_utils_1.isDeleted)(footnotesElement.node) &&
748
745
  !(0, track_changes_utils_1.isRejectedInsert)(footnotesElement.node)) {
749
- const pos = footnotesElement.pos;
750
- insertionPos = position + pos + footnotesElement.node.nodeSize + 1;
746
+ const footnotePos = (0, footnotes_utils_1.getNewFootnotePos)(footnotesElement, tablesFootnoteLabels, footnoteIndex);
747
+ insertionPos = tr.mapping.map(position + footnotesElement.pos + footnotePos);
751
748
  tr.insert(insertionPos, footnote);
752
749
  }
753
750
  else {
754
751
  const footnoteElement = state.schema.nodes.footnotes_element.create({}, footnote);
755
- const tableElementFooter = (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.table_element_footer);
756
- if (tableElementFooter.length) {
757
- const pos = tableElementFooter[0].pos;
758
- insertionPos = position + pos + tableElementFooter[0].node.nodeSize + 1;
752
+ const tableElementFooter = (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.table_element_footer)[0];
753
+ if (tableElementFooter) {
754
+ const pos = tableElementFooter.pos;
755
+ insertionPos = position + pos + tableElementFooter.node.nodeSize;
759
756
  tr.insert(insertionPos, footnoteElement);
760
757
  }
761
758
  else {
@@ -765,21 +762,25 @@ const insertTableFootnote = (node, position, state, dispatch) => {
765
762
  const tableColGroup = (0, prosemirror_utils_1.findChildrenByType)(node, transform_1.schema.nodes.table_colgroup)[0];
766
763
  if (tableColGroup) {
767
764
  insertionPos =
768
- position + tableColGroup.pos + tableColGroup.node.nodeSize + 2;
765
+ position + tableColGroup.pos + tableColGroup.node.nodeSize;
769
766
  tr.insert(insertionPos, tableElementFooter);
770
767
  }
771
768
  else {
772
769
  const tableSize = (_a = node.content.firstChild) === null || _a === void 0 ? void 0 : _a.nodeSize;
773
770
  if (tableSize) {
774
- insertionPos = position + tableSize + 2;
771
+ insertionPos = position + tableSize;
775
772
  tr.insert(insertionPos, tableElementFooter);
776
773
  }
777
774
  }
778
775
  }
779
776
  }
780
- if (dispatch && insertionPos) {
781
- const nodeSelection = prosemirror_state_1.NodeSelection.create(tr.doc, insertionPos);
782
- dispatch(tr.setSelection(nodeSelection));
783
- }
777
+ const textSelection = prosemirror_state_1.TextSelection.near(tr.doc.resolve(insertionPos + 1));
778
+ view.focus();
779
+ tr.setSelection(textSelection);
780
+ const inlineFootnoteNode = state.schema.nodes.inline_footnote.create({
781
+ rids: [footnote.attrs.id],
782
+ contents: (footnoteIndex === -1 ? inlineFootnotes.length : footnoteIndex) + 1,
783
+ });
784
+ dispatch(tr.insert(insertedAt, inlineFootnoteNode).scrollIntoView());
784
785
  };
785
786
  exports.insertTableFootnote = insertTableFootnote;
@@ -20,6 +20,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  require("prosemirror-gapcursor/style/gapcursor.css");
22
22
  require("prosemirror-tables/style/tables.css");
23
+ const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
23
24
  const prosemirror_collab_1 = require("prosemirror-collab");
24
25
  const prosemirror_dropcursor_1 = require("prosemirror-dropcursor");
25
26
  const prosemirror_history_1 = require("prosemirror-history");
@@ -41,13 +42,18 @@ const tables_cursor_fix_1 = __importDefault(require("../plugins/tables-cursor-fi
41
42
  const toc_1 = __importDefault(require("../plugins/toc"));
42
43
  const rules_1 = __importDefault(require("../rules"));
43
44
  exports.default = (props) => {
44
- const plugins = props.plugins || [];
45
45
  const allPlugins = [
46
46
  rules_1.default,
47
47
  ...keys_1.default,
48
48
  (0, prosemirror_dropcursor_1.dropCursor)(),
49
49
  (0, prosemirror_history_1.history)(),
50
- ...plugins,
50
+ (0, track_changes_plugin_1.trackChangesPlugin)({
51
+ userID: props.userID,
52
+ debug: props.debug,
53
+ initialStatus: props.getCapabilities().editWithoutTracking
54
+ ? track_changes_plugin_1.TrackChangesStatus.disabled
55
+ : track_changes_plugin_1.TrackChangesStatus.enabled,
56
+ }),
51
57
  (0, tables_cursor_fix_1.default)(),
52
58
  (0, elements_1.default)(),
53
59
  (0, persist_1.default)(),
@@ -23,9 +23,11 @@ const style_guide_1 = require("@manuscripts/style-guide");
23
23
  const transform_1 = require("@manuscripts/transform");
24
24
  const prosemirror_utils_1 = require("prosemirror-utils");
25
25
  const commands_1 = require("../commands");
26
+ const footnotes_1 = require("../plugins/footnotes");
26
27
  const ReactSubView_1 = __importDefault(require("../views/ReactSubView"));
27
28
  const popper_1 = require("./popper");
28
29
  const track_changes_utils_1 = require("./track-changes-utils");
30
+ const utils_1 = require("./utils");
29
31
  const popper = new popper_1.PopperManager();
30
32
  const listTypes = [transform_1.schema.nodes.ordered_list, transform_1.schema.nodes.bullet_list];
31
33
  const readonlyTypes = [transform_1.schema.nodes.keywords, transform_1.schema.nodes.bibliography_element];
@@ -188,37 +190,50 @@ class ContextMenu {
188
190
  menu.appendChild(this.createMenuSection((section) => {
189
191
  section.appendChild(this.createMenuItem('Add Reference Note', () => {
190
192
  var _a, _b;
191
- const footnotesElement = (_a = (0, prosemirror_utils_1.findChildrenByType)(this.node, transform_1.schema.nodes.footnotes_element).pop()) === null || _a === void 0 ? void 0 : _a.node;
192
- if (!footnotesElement ||
193
- (0, track_changes_utils_1.isDeleted)(footnotesElement) ||
194
- (0, track_changes_utils_1.isRejectedInsert)(footnotesElement)) {
195
- const { state, dispatch } = this.view;
196
- (0, commands_1.insertTableFootnote)(this.node, this.getPos(), state, dispatch);
193
+ const footnotesElementWithPos = (0, prosemirror_utils_1.findChildrenByType)(this.node, transform_1.schema.nodes.footnotes_element)[0];
194
+ if (!footnotesElementWithPos ||
195
+ (0, track_changes_utils_1.isDeleted)(footnotesElementWithPos.node) ||
196
+ (0, track_changes_utils_1.isRejectedInsert)(footnotesElementWithPos.node)) {
197
+ (0, commands_1.insertTableFootnote)(this.node, this.getPos(), this.view);
197
198
  }
198
199
  else {
199
- const footnotes = (0, prosemirror_utils_1.findChildrenByType)(footnotesElement, transform_1.schema.nodes.footnote).map((nodeWithPos) => {
200
- return nodeWithPos.node;
201
- });
200
+ const tablesFootnoteLabels = ((_a = footnotes_1.footnotesKey
201
+ .getState(this.view.state)) === null || _a === void 0 ? void 0 : _a.tablesFootnoteLabels.get(this.node.attrs.id)) ||
202
+ new Map();
203
+ const footnotesWithPos = (0, prosemirror_utils_1.findChildrenByType)(footnotesElementWithPos.node, transform_1.schema.nodes.footnote);
204
+ const footnotes = footnotesWithPos.map((nodeWithPos) => ({
205
+ node: nodeWithPos.node,
206
+ index: tablesFootnoteLabels.get(nodeWithPos.node.attrs.id),
207
+ }));
202
208
  const targetDom = this.view.domAtPos(this.view.state.selection.from);
203
209
  if (targetDom.node instanceof Element && this.props) {
204
210
  const popperContainer = (0, ReactSubView_1.default)(Object.assign(Object.assign({}, this.props), { dispatch: this.view.dispatch }), style_guide_1.TableFootnotesSelector, {
205
211
  notes: footnotes,
206
212
  onAdd: () => {
207
213
  var _a;
208
- const { state, dispatch } = this.view;
209
- (0, commands_1.insertTableFootnote)(this.node, this.getPos(), state, dispatch);
214
+ (0, commands_1.insertTableFootnote)(this.node, this.getPos(), this.view, tablesFootnoteLabels);
210
215
  (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
211
216
  },
212
217
  onInsert: (notes) => {
213
218
  var _a;
214
219
  const insertedAt = this.view.state.selection.to;
220
+ let inlineFootnoteIndex = 1;
221
+ this.view.state.doc
222
+ .slice(this.getPos(), insertedAt)
223
+ .content.descendants((node) => {
224
+ if (node.type === transform_1.schema.nodes.inline_footnote) {
225
+ inlineFootnoteIndex++;
226
+ return false;
227
+ }
228
+ });
215
229
  const node = this.view.state.schema.nodes.inline_footnote.create({
216
- rids: notes.map((note) => note.attrs.id),
230
+ rids: notes.map(({ node }) => node.attrs.id),
217
231
  contents: notes
218
- .map((note) => footnotes.indexOf(note) + 1)
232
+ .map(({ index }) => index ? index : inlineFootnoteIndex)
219
233
  .join(),
220
234
  });
221
235
  const tr = this.view.state.tr;
236
+ (0, utils_1.orderTableFootnotes)(tr, notes.map(({ node }) => node), footnotes, footnotesElementWithPos, this.getPos(), inlineFootnoteIndex);
222
237
  tr.insert(insertedAt, node);
223
238
  this.view.dispatch(tr);
224
239
  (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2024 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.getNewFootnotePos = void 0;
19
+ const prosemirror_utils_1 = require("prosemirror-utils");
20
+ const getNewFootnotePos = (footnotesElement, tablesFootnoteLabels, footnoteIndex) => {
21
+ var _a;
22
+ const citedFootnotes = (0, prosemirror_utils_1.flatten)(footnotesElement.node, false).filter(({ node }) => tablesFootnoteLabels === null || tablesFootnoteLabels === void 0 ? void 0 : tablesFootnoteLabels.has(node.attrs.id));
23
+ if (citedFootnotes.length === 0 || footnoteIndex === 0) {
24
+ return 2;
25
+ }
26
+ if (footnoteIndex === -1) {
27
+ const lastChild = citedFootnotes[citedFootnotes.length - 1];
28
+ return (lastChild && lastChild.pos + lastChild.node.nodeSize) || 1;
29
+ }
30
+ return ((_a = citedFootnotes[footnoteIndex]) === null || _a === void 0 ? void 0 : _a.pos) || 0;
31
+ };
32
+ exports.getNewFootnotePos = getNewFootnotePos;
@@ -15,8 +15,9 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.findParentElement = exports.findParentSection = exports.findParentNodeWithIdValue = exports.findParentNodeWithId = exports.getChildOfType = exports.getMatchingDescendant = exports.getMatchingChild = exports.iterateChildren = void 0;
18
+ exports.orderTableFootnotes = exports.findParentElement = exports.findParentSection = exports.findParentNodeWithIdValue = exports.findParentNodeWithId = exports.getChildOfType = exports.getMatchingDescendant = exports.getMatchingChild = exports.iterateChildren = void 0;
19
19
  const transform_1 = require("@manuscripts/transform");
20
+ const prosemirror_model_1 = require("prosemirror-model");
20
21
  const prosemirror_utils_1 = require("prosemirror-utils");
21
22
  function* iterateChildren(node, recurse = false) {
22
23
  for (let i = 0; i < node.childCount; i++) {
@@ -58,3 +59,22 @@ const findParentElement = (selection, validIds) => (0, prosemirror_utils_1.findP
58
59
  return (0, transform_1.isElementNodeType)(node.type) && node.attrs.id;
59
60
  })(selection);
60
61
  exports.findParentElement = findParentElement;
62
+ const orderTableFootnotes = (tr, notes, footnotes, footnotesElementWithPos, position, inlineFootnoteIndex) => {
63
+ const selectedNoteMap = new Map(notes.map((note) => [note.attrs.id, note]));
64
+ const orderedFootnotes = [...footnotes]
65
+ .map((note) => {
66
+ if (selectedNoteMap.has(note.node.attrs.id)) {
67
+ return Object.assign(Object.assign({}, note), { index: inlineFootnoteIndex++ });
68
+ }
69
+ if (note.index && note.index <= inlineFootnoteIndex) {
70
+ return Object.assign(Object.assign({}, note), { index: note.index + 1 });
71
+ }
72
+ return note;
73
+ })
74
+ .sort(({ index: i1 }, { index: i2 }) => (i1 && i2 ? i1 - i2 : -1))
75
+ .map(({ node }) => node);
76
+ const { node: footnotesElement, pos } = footnotesElementWithPos;
77
+ const footnoteElementPos = position + pos;
78
+ tr.replaceWith(footnoteElementPos, footnoteElementPos + footnotesElement.nodeSize, prosemirror_model_1.Fragment.fromArray(orderedFootnotes));
79
+ };
80
+ exports.orderTableFootnotes = orderTableFootnotes;
@@ -30,6 +30,7 @@ const buildPluginState = (doc) => {
30
30
  const nodes = [];
31
31
  let index = 0;
32
32
  const labels = new Map();
33
+ const tablesFootnoteLabels = new Map();
33
34
  doc.descendants((node, pos, parentNode) => {
34
35
  if ((0, transform_1.isInlineFootnoteNode)(node) &&
35
36
  parentNode &&
@@ -39,8 +40,20 @@ const buildPluginState = (doc) => {
39
40
  labels.set(rid, String(++index));
40
41
  });
41
42
  }
43
+ if (node.type === transform_1.schema.nodes.table_element) {
44
+ let tableFootnoteIndex = 0, labelsMap = new Map();
45
+ node.descendants((child, childPos) => {
46
+ if ((0, transform_1.isInlineFootnoteNode)(child)) {
47
+ nodes.push([child, pos + childPos + child.nodeSize]);
48
+ child.attrs.rids.map((rid) => labelsMap.set(rid, ++tableFootnoteIndex));
49
+ }
50
+ });
51
+ tablesFootnoteLabels.set(node.attrs.id, labelsMap);
52
+ labelsMap = new Map();
53
+ return false;
54
+ }
42
55
  });
43
- return { nodes, labels };
56
+ return { nodes, labels, tablesFootnoteLabels };
44
57
  };
45
58
  exports.buildPluginState = buildPluginState;
46
59
  const scrollToInlineFootnote = (rid, view) => {
@@ -81,15 +94,19 @@ exports.default = () => {
81
94
  },
82
95
  appendTransaction(transactions, oldState, newState) {
83
96
  const { nodes: oldInlineFootnoteNodes } = exports.footnotesKey.getState(oldState);
84
- const { nodes: inlineFootnoteNodes, labels } = exports.footnotesKey.getState(newState);
97
+ const { nodes: inlineFootnoteNodes, labels, tablesFootnoteLabels, } = exports.footnotesKey.getState(newState);
85
98
  if ((0, lodash_1.isEqual)(inlineFootnoteNodes, oldInlineFootnoteNodes)) {
86
99
  return null;
87
100
  }
101
+ const updatedLabels = Array.from(tablesFootnoteLabels.values()).reduce((labels, footnoteLabels) => {
102
+ Array.from(footnoteLabels.entries()).map(([id, content]) => labels.set(id, content.toString()));
103
+ return labels;
104
+ }, labels);
88
105
  const { tr } = newState;
89
106
  inlineFootnoteNodes.forEach(([node, pos]) => {
90
107
  const footnote = node;
91
108
  const contents = footnote.attrs.rids
92
- .map((rid) => labels.get(rid))
109
+ .map((rid) => updatedLabels.get(rid))
93
110
  .join('');
94
111
  if (footnote.attrs.contents !== contents) {
95
112
  tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, footnote.attrs), { rids: footnote.attrs.rids, contents }));
@@ -81,10 +81,8 @@ exports.defaultEditorProps = {
81
81
  locale: '',
82
82
  },
83
83
  getCitationProvider: () => undefined,
84
- plugins: [],
85
84
  retrySync: () => Promise.resolve(),
86
85
  setComment: () => undefined,
87
86
  setSelectedComment: () => undefined,
88
87
  setEditorSelectedSuggestion: () => undefined,
89
- environment: undefined,
90
88
  };
@@ -60,8 +60,7 @@ const useEditor = (props) => {
60
60
  view.current.updateState(nextState);
61
61
  const trackState = track_changes_plugin_1.trackChangesPluginKey.getState(view.current.state);
62
62
  if (collabProvider &&
63
- trackState &&
64
- trackState.status !== track_changes_plugin_1.TrackChangesStatus.viewSnapshots) {
63
+ (!trackState || trackState.status !== track_changes_plugin_1.TrackChangesStatus.viewSnapshots)) {
65
64
  const sendable = (0, prosemirror_collab_1.sendableSteps)(nextState);
66
65
  if (sendable) {
67
66
  collabProvider.sendSteps(sendable.version, sendable.steps, sendable.clientID, !tr.isGeneric);
@@ -22,6 +22,7 @@ import { NodeSelection, TextSelection, } from 'prosemirror-state';
22
22
  import { findWrapping } from 'prosemirror-transform';
23
23
  import { findChildrenByType, findParentNodeOfType, } from 'prosemirror-utils';
24
24
  import { skipCommandTracking } from './keys/list';
25
+ import { getNewFootnotePos } from './lib/footnotes-utils';
25
26
  import { isNodeOfType, nearestAncestor } from './lib/helpers';
26
27
  import { isDeleted, isRejectedInsert } from './lib/track-changes-utils';
27
28
  import { findParentNodeWithId, getChildOfType } from './lib/utils';
@@ -689,36 +690,32 @@ export const updateCommentAnnotationState = (state, dispatch) => {
689
690
  dispatch(tr);
690
691
  }
691
692
  };
692
- export const insertTableFootnote = (node, position, state, dispatch) => {
693
+ export const insertTableFootnote = (node, position, view, tablesFootnoteLabels) => {
693
694
  var _a;
695
+ const { state, dispatch } = view;
694
696
  const footnote = state.schema.nodes.footnote.createAndFill({
695
697
  id: generateID(ObjectTypes.Footnote),
696
698
  kind: 'footnote',
697
699
  });
698
700
  const insertedAt = state.selection.to;
699
701
  const inlineFootnotes = findChildrenByType(node, schema.nodes.inline_footnote);
700
- const labels = inlineFootnotes.map((nodeWithPos) => nodeWithPos.node.attrs.contents);
701
- const inlineFootnoteNode = state.schema.nodes.inline_footnote.create({
702
- rids: [footnote.attrs.id],
703
- contents: labels.length ? Math.max(...labels) + 1 : 1,
704
- });
702
+ const footnoteIndex = inlineFootnotes.filter(({ pos }) => position + pos >= insertedAt).length - 1;
705
703
  const tr = state.tr;
706
- tr.insert(insertedAt, inlineFootnoteNode);
707
- let insertionPos;
708
- const footnotesElement = findChildrenByType(node, schema.nodes.footnotes_element).pop();
704
+ let insertionPos = position;
705
+ const footnotesElement = findChildrenByType(node, schema.nodes.footnotes_element)[0];
709
706
  if (footnotesElement &&
710
707
  !isDeleted(footnotesElement.node) &&
711
708
  !isRejectedInsert(footnotesElement.node)) {
712
- const pos = footnotesElement.pos;
713
- insertionPos = position + pos + footnotesElement.node.nodeSize + 1;
709
+ const footnotePos = getNewFootnotePos(footnotesElement, tablesFootnoteLabels, footnoteIndex);
710
+ insertionPos = tr.mapping.map(position + footnotesElement.pos + footnotePos);
714
711
  tr.insert(insertionPos, footnote);
715
712
  }
716
713
  else {
717
714
  const footnoteElement = state.schema.nodes.footnotes_element.create({}, footnote);
718
- const tableElementFooter = findChildrenByType(node, schema.nodes.table_element_footer);
719
- if (tableElementFooter.length) {
720
- const pos = tableElementFooter[0].pos;
721
- insertionPos = position + pos + tableElementFooter[0].node.nodeSize + 1;
715
+ const tableElementFooter = findChildrenByType(node, schema.nodes.table_element_footer)[0];
716
+ if (tableElementFooter) {
717
+ const pos = tableElementFooter.pos;
718
+ insertionPos = position + pos + tableElementFooter.node.nodeSize;
722
719
  tr.insert(insertionPos, footnoteElement);
723
720
  }
724
721
  else {
@@ -728,20 +725,24 @@ export const insertTableFootnote = (node, position, state, dispatch) => {
728
725
  const tableColGroup = findChildrenByType(node, schema.nodes.table_colgroup)[0];
729
726
  if (tableColGroup) {
730
727
  insertionPos =
731
- position + tableColGroup.pos + tableColGroup.node.nodeSize + 2;
728
+ position + tableColGroup.pos + tableColGroup.node.nodeSize;
732
729
  tr.insert(insertionPos, tableElementFooter);
733
730
  }
734
731
  else {
735
732
  const tableSize = (_a = node.content.firstChild) === null || _a === void 0 ? void 0 : _a.nodeSize;
736
733
  if (tableSize) {
737
- insertionPos = position + tableSize + 2;
734
+ insertionPos = position + tableSize;
738
735
  tr.insert(insertionPos, tableElementFooter);
739
736
  }
740
737
  }
741
738
  }
742
739
  }
743
- if (dispatch && insertionPos) {
744
- const nodeSelection = NodeSelection.create(tr.doc, insertionPos);
745
- dispatch(tr.setSelection(nodeSelection));
746
- }
740
+ const textSelection = TextSelection.near(tr.doc.resolve(insertionPos + 1));
741
+ view.focus();
742
+ tr.setSelection(textSelection);
743
+ const inlineFootnoteNode = state.schema.nodes.inline_footnote.create({
744
+ rids: [footnote.attrs.id],
745
+ contents: (footnoteIndex === -1 ? inlineFootnotes.length : footnoteIndex) + 1,
746
+ });
747
+ dispatch(tr.insert(insertedAt, inlineFootnoteNode).scrollIntoView());
747
748
  };
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import 'prosemirror-gapcursor/style/gapcursor.css';
17
17
  import 'prosemirror-tables/style/tables.css';
18
+ import { trackChangesPlugin, TrackChangesStatus, } from '@manuscripts/track-changes-plugin';
18
19
  import { collab } from 'prosemirror-collab';
19
20
  import { dropCursor } from 'prosemirror-dropcursor';
20
21
  import { history } from 'prosemirror-history';
@@ -36,13 +37,18 @@ import table_editing_fix from '../plugins/tables-cursor-fix';
36
37
  import toc from '../plugins/toc';
37
38
  import rules from '../rules';
38
39
  export default (props) => {
39
- const plugins = props.plugins || [];
40
40
  const allPlugins = [
41
41
  rules,
42
42
  ...keys,
43
43
  dropCursor(),
44
44
  history(),
45
- ...plugins,
45
+ trackChangesPlugin({
46
+ userID: props.userID,
47
+ debug: props.debug,
48
+ initialStatus: props.getCapabilities().editWithoutTracking
49
+ ? TrackChangesStatus.disabled
50
+ : TrackChangesStatus.enabled,
51
+ }),
46
52
  table_editing_fix(),
47
53
  elements(),
48
54
  persist(),
@@ -13,13 +13,15 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { TableFootnotesSelector } from '@manuscripts/style-guide';
16
+ import { TableFootnotesSelector, } from '@manuscripts/style-guide';
17
17
  import { isInBibliographySection, nodeNames, schema, } from '@manuscripts/transform';
18
18
  import { findChildrenByType, hasParentNodeOfType } from 'prosemirror-utils';
19
19
  import { addComment, createBlock, insertGeneralFootnote, insertTableFootnote, } from '../commands';
20
+ import { footnotesKey } from '../plugins/footnotes';
20
21
  import ReactSubView from '../views/ReactSubView';
21
22
  import { PopperManager } from './popper';
22
23
  import { isDeleted, isRejectedInsert } from './track-changes-utils';
24
+ import { orderTableFootnotes } from './utils';
23
25
  const popper = new PopperManager();
24
26
  const listTypes = [schema.nodes.ordered_list, schema.nodes.bullet_list];
25
27
  const readonlyTypes = [schema.nodes.keywords, schema.nodes.bibliography_element];
@@ -181,37 +183,50 @@ export class ContextMenu {
181
183
  menu.appendChild(this.createMenuSection((section) => {
182
184
  section.appendChild(this.createMenuItem('Add Reference Note', () => {
183
185
  var _a, _b;
184
- const footnotesElement = (_a = findChildrenByType(this.node, schema.nodes.footnotes_element).pop()) === null || _a === void 0 ? void 0 : _a.node;
185
- if (!footnotesElement ||
186
- isDeleted(footnotesElement) ||
187
- isRejectedInsert(footnotesElement)) {
188
- const { state, dispatch } = this.view;
189
- insertTableFootnote(this.node, this.getPos(), state, dispatch);
186
+ const footnotesElementWithPos = findChildrenByType(this.node, schema.nodes.footnotes_element)[0];
187
+ if (!footnotesElementWithPos ||
188
+ isDeleted(footnotesElementWithPos.node) ||
189
+ isRejectedInsert(footnotesElementWithPos.node)) {
190
+ insertTableFootnote(this.node, this.getPos(), this.view);
190
191
  }
191
192
  else {
192
- const footnotes = findChildrenByType(footnotesElement, schema.nodes.footnote).map((nodeWithPos) => {
193
- return nodeWithPos.node;
194
- });
193
+ const tablesFootnoteLabels = ((_a = footnotesKey
194
+ .getState(this.view.state)) === null || _a === void 0 ? void 0 : _a.tablesFootnoteLabels.get(this.node.attrs.id)) ||
195
+ new Map();
196
+ const footnotesWithPos = findChildrenByType(footnotesElementWithPos.node, schema.nodes.footnote);
197
+ const footnotes = footnotesWithPos.map((nodeWithPos) => ({
198
+ node: nodeWithPos.node,
199
+ index: tablesFootnoteLabels.get(nodeWithPos.node.attrs.id),
200
+ }));
195
201
  const targetDom = this.view.domAtPos(this.view.state.selection.from);
196
202
  if (targetDom.node instanceof Element && this.props) {
197
203
  const popperContainer = ReactSubView(Object.assign(Object.assign({}, this.props), { dispatch: this.view.dispatch }), TableFootnotesSelector, {
198
204
  notes: footnotes,
199
205
  onAdd: () => {
200
206
  var _a;
201
- const { state, dispatch } = this.view;
202
- insertTableFootnote(this.node, this.getPos(), state, dispatch);
207
+ insertTableFootnote(this.node, this.getPos(), this.view, tablesFootnoteLabels);
203
208
  (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
204
209
  },
205
210
  onInsert: (notes) => {
206
211
  var _a;
207
212
  const insertedAt = this.view.state.selection.to;
213
+ let inlineFootnoteIndex = 1;
214
+ this.view.state.doc
215
+ .slice(this.getPos(), insertedAt)
216
+ .content.descendants((node) => {
217
+ if (node.type === schema.nodes.inline_footnote) {
218
+ inlineFootnoteIndex++;
219
+ return false;
220
+ }
221
+ });
208
222
  const node = this.view.state.schema.nodes.inline_footnote.create({
209
- rids: notes.map((note) => note.attrs.id),
223
+ rids: notes.map(({ node }) => node.attrs.id),
210
224
  contents: notes
211
- .map((note) => footnotes.indexOf(note) + 1)
225
+ .map(({ index }) => index ? index : inlineFootnoteIndex)
212
226
  .join(),
213
227
  });
214
228
  const tr = this.view.state.tr;
229
+ orderTableFootnotes(tr, notes.map(({ node }) => node), footnotes, footnotesElementWithPos, this.getPos(), inlineFootnoteIndex);
215
230
  tr.insert(insertedAt, node);
216
231
  this.view.dispatch(tr);
217
232
  (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
@@ -0,0 +1,28 @@
1
+ /*!
2
+ * © 2024 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { flatten } from 'prosemirror-utils';
17
+ export const getNewFootnotePos = (footnotesElement, tablesFootnoteLabels, footnoteIndex) => {
18
+ var _a;
19
+ const citedFootnotes = flatten(footnotesElement.node, false).filter(({ node }) => tablesFootnoteLabels === null || tablesFootnoteLabels === void 0 ? void 0 : tablesFootnoteLabels.has(node.attrs.id));
20
+ if (citedFootnotes.length === 0 || footnoteIndex === 0) {
21
+ return 2;
22
+ }
23
+ if (footnoteIndex === -1) {
24
+ const lastChild = citedFootnotes[citedFootnotes.length - 1];
25
+ return (lastChild && lastChild.pos + lastChild.node.nodeSize) || 1;
26
+ }
27
+ return ((_a = citedFootnotes[footnoteIndex]) === null || _a === void 0 ? void 0 : _a.pos) || 0;
28
+ };
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { isElementNodeType, isSectionNodeType, } from '@manuscripts/transform';
17
+ import { Fragment } from 'prosemirror-model';
17
18
  import { findParentNode } from 'prosemirror-utils';
18
19
  export function* iterateChildren(node, recurse = false) {
19
20
  for (let i = 0; i < node.childCount; i++) {
@@ -50,3 +51,21 @@ export const findParentElement = (selection, validIds) => findParentNode((node)
50
51
  }
51
52
  return isElementNodeType(node.type) && node.attrs.id;
52
53
  })(selection);
54
+ export const orderTableFootnotes = (tr, notes, footnotes, footnotesElementWithPos, position, inlineFootnoteIndex) => {
55
+ const selectedNoteMap = new Map(notes.map((note) => [note.attrs.id, note]));
56
+ const orderedFootnotes = [...footnotes]
57
+ .map((note) => {
58
+ if (selectedNoteMap.has(note.node.attrs.id)) {
59
+ return Object.assign(Object.assign({}, note), { index: inlineFootnoteIndex++ });
60
+ }
61
+ if (note.index && note.index <= inlineFootnoteIndex) {
62
+ return Object.assign(Object.assign({}, note), { index: note.index + 1 });
63
+ }
64
+ return note;
65
+ })
66
+ .sort(({ index: i1 }, { index: i2 }) => (i1 && i2 ? i1 - i2 : -1))
67
+ .map(({ node }) => node);
68
+ const { node: footnotesElement, pos } = footnotesElementWithPos;
69
+ const footnoteElementPos = position + pos;
70
+ tr.replaceWith(footnoteElementPos, footnoteElementPos + footnotesElement.nodeSize, Fragment.fromArray(orderedFootnotes));
71
+ };
@@ -27,6 +27,7 @@ export const buildPluginState = (doc) => {
27
27
  const nodes = [];
28
28
  let index = 0;
29
29
  const labels = new Map();
30
+ const tablesFootnoteLabels = new Map();
30
31
  doc.descendants((node, pos, parentNode) => {
31
32
  if (isInlineFootnoteNode(node) &&
32
33
  parentNode &&
@@ -36,8 +37,20 @@ export const buildPluginState = (doc) => {
36
37
  labels.set(rid, String(++index));
37
38
  });
38
39
  }
40
+ if (node.type === schema.nodes.table_element) {
41
+ let tableFootnoteIndex = 0, labelsMap = new Map();
42
+ node.descendants((child, childPos) => {
43
+ if (isInlineFootnoteNode(child)) {
44
+ nodes.push([child, pos + childPos + child.nodeSize]);
45
+ child.attrs.rids.map((rid) => labelsMap.set(rid, ++tableFootnoteIndex));
46
+ }
47
+ });
48
+ tablesFootnoteLabels.set(node.attrs.id, labelsMap);
49
+ labelsMap = new Map();
50
+ return false;
51
+ }
39
52
  });
40
- return { nodes, labels };
53
+ return { nodes, labels, tablesFootnoteLabels };
41
54
  };
42
55
  const scrollToInlineFootnote = (rid, view) => {
43
56
  view.state.doc.descendants((node, pos) => {
@@ -76,15 +89,19 @@ export default () => {
76
89
  },
77
90
  appendTransaction(transactions, oldState, newState) {
78
91
  const { nodes: oldInlineFootnoteNodes } = footnotesKey.getState(oldState);
79
- const { nodes: inlineFootnoteNodes, labels } = footnotesKey.getState(newState);
92
+ const { nodes: inlineFootnoteNodes, labels, tablesFootnoteLabels, } = footnotesKey.getState(newState);
80
93
  if (isEqual(inlineFootnoteNodes, oldInlineFootnoteNodes)) {
81
94
  return null;
82
95
  }
96
+ const updatedLabels = Array.from(tablesFootnoteLabels.values()).reduce((labels, footnoteLabels) => {
97
+ Array.from(footnoteLabels.entries()).map(([id, content]) => labels.set(id, content.toString()));
98
+ return labels;
99
+ }, labels);
83
100
  const { tr } = newState;
84
101
  inlineFootnoteNodes.forEach(([node, pos]) => {
85
102
  const footnote = node;
86
103
  const contents = footnote.attrs.rids
87
- .map((rid) => labels.get(rid))
104
+ .map((rid) => updatedLabels.get(rid))
88
105
  .join('');
89
106
  if (footnote.attrs.contents !== contents) {
90
107
  tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, footnote.attrs), { rids: footnote.attrs.rids, contents }));
@@ -75,10 +75,8 @@ export const defaultEditorProps = {
75
75
  locale: '',
76
76
  },
77
77
  getCitationProvider: () => undefined,
78
- plugins: [],
79
78
  retrySync: () => Promise.resolve(),
80
79
  setComment: () => undefined,
81
80
  setSelectedComment: () => undefined,
82
81
  setEditorSelectedSuggestion: () => undefined,
83
- environment: undefined,
84
82
  };
@@ -57,8 +57,7 @@ export const useEditor = (props) => {
57
57
  view.current.updateState(nextState);
58
58
  const trackState = trackChangesPluginKey.getState(view.current.state);
59
59
  if (collabProvider &&
60
- trackState &&
61
- trackState.status !== TrackChangesStatus.viewSnapshots) {
60
+ (!trackState || trackState.status !== TrackChangesStatus.viewSnapshots)) {
62
61
  const sendable = sendableSteps(nextState);
63
62
  if (sendable) {
64
63
  collabProvider.sendSteps(sendable.version, sendable.steps, sendable.clientID, !tr.isGeneric);
@@ -19,6 +19,7 @@ import { ManuscriptEditorState, ManuscriptEditorView, ManuscriptMarkType, Manusc
19
19
  import { ResolvedPos } from 'prosemirror-model';
20
20
  import { Command, NodeSelection, Selection, TextSelection, Transaction } from 'prosemirror-state';
21
21
  import { NodeWithPos } from 'prosemirror-utils';
22
+ import { EditorView } from 'prosemirror-view';
22
23
  import { EditorAction } from './types';
23
24
  export type Dispatch = (tr: ManuscriptTransaction) => void;
24
25
  export declare const markActive: (type: ManuscriptMarkType) => (state: ManuscriptEditorState) => boolean;
@@ -56,4 +57,4 @@ export declare const deleteHighlightMarkers: (rid: string) => Command;
56
57
  export declare function addComment(state: ManuscriptEditorState, dispatch?: Dispatch): boolean;
57
58
  export declare function addComment(state: ManuscriptEditorState, dispatch?: Dispatch, viewNode?: ManuscriptNode, resolvePos?: ResolvedPos): boolean;
58
59
  export declare const updateCommentAnnotationState: (state: ManuscriptEditorState, dispatch?: Dispatch) => void;
59
- export declare const insertTableFootnote: (node: ManuscriptNode, position: number, state: ManuscriptEditorState, dispatch?: Dispatch) => void;
60
+ export declare const insertTableFootnote: (node: ManuscriptNode, position: number, view: EditorView, tablesFootnoteLabels?: Map<string, number>) => void;
@@ -18,7 +18,7 @@ import { CommentAnnotation, Manuscript, UserProfile } from '@manuscripts/json-sc
18
18
  import { Capabilities, FileAttachment, FileManagement } from '@manuscripts/style-guide';
19
19
  import { ManuscriptNode } from '@manuscripts/transform';
20
20
  import { History } from 'history';
21
- import { EditorState, Plugin } from 'prosemirror-state';
21
+ import { EditorState } from 'prosemirror-state';
22
22
  import { EditorView } from 'prosemirror-view';
23
23
  import { DefaultTheme } from 'styled-components';
24
24
  import { CollabProvider } from '../classes/collabProvider';
@@ -34,7 +34,6 @@ export interface EditorProps {
34
34
  };
35
35
  locale: string;
36
36
  theme: DefaultTheme;
37
- plugins?: Plugin[];
38
37
  getCurrentUser: () => UserProfile;
39
38
  projectID: string;
40
39
  doc: ManuscriptNode;
@@ -44,12 +43,13 @@ export interface EditorProps {
44
43
  popper: PopperManager;
45
44
  history: History;
46
45
  getCapabilities: () => Capabilities;
46
+ userID: string;
47
+ debug: boolean;
47
48
  cslProps: CSLProps;
48
49
  setComment: (comment?: CommentAnnotation) => void;
49
50
  setSelectedComment: (id?: string) => void;
50
51
  setEditorSelectedSuggestion: (id?: string) => void;
51
52
  retrySync: (componentIDs: string[]) => Promise<void>;
52
- environment?: string;
53
53
  collabProvider?: CollabProvider;
54
54
  }
55
55
  export declare const createEditorState: (props: EditorProps) => EditorState;
@@ -32,6 +32,8 @@ interface PluginProps {
32
32
  cslProps: CSLProps;
33
33
  popper: PopperManager;
34
34
  collabProvider?: CollabProvider;
35
+ userID: string;
36
+ debug: boolean;
35
37
  }
36
38
  declare const _default: (props: PluginProps) => any[];
37
39
  export default _default;
@@ -0,0 +1,17 @@
1
+ /*!
2
+ * © 2024 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { NodeWithPos } from 'prosemirror-utils';
17
+ export declare const getNewFootnotePos: (footnotesElement: NodeWithPos, tablesFootnoteLabels: Map<string, number> | undefined, footnoteIndex: number) => number;
@@ -13,8 +13,9 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { ManuscriptNode, ManuscriptNodeType } from '@manuscripts/transform';
17
- import { Selection } from 'prosemirror-state';
16
+ import { FootnoteNode, ManuscriptNode, ManuscriptNodeType } from '@manuscripts/transform';
17
+ import { Selection, Transaction } from 'prosemirror-state';
18
+ import { NodeWithPos } from 'prosemirror-utils';
18
19
  export declare function iterateChildren(node: ManuscriptNode, recurse?: boolean): Iterable<ManuscriptNode>;
19
20
  export declare const getMatchingChild: (parent: ManuscriptNode, matcher: (node: ManuscriptNode) => boolean, deep?: boolean) => ManuscriptNode | undefined;
20
21
  export declare const getMatchingDescendant: (parent: ManuscriptNode, matcher: (node: ManuscriptNode) => boolean) => ManuscriptNode | undefined;
@@ -23,3 +24,7 @@ export declare const findParentNodeWithId: (selection: Selection) => import("pro
23
24
  export declare const findParentNodeWithIdValue: (selection: Selection) => import("prosemirror-utils").ContentNodeWithPos | undefined;
24
25
  export declare const findParentSection: (selection: Selection) => import("prosemirror-utils").ContentNodeWithPos | undefined;
25
26
  export declare const findParentElement: (selection: Selection, validIds?: string[]) => import("prosemirror-utils").ContentNodeWithPos | undefined;
27
+ export declare const orderTableFootnotes: (tr: Transaction, notes: FootnoteNode[], footnotes: {
28
+ node: ManuscriptNode;
29
+ index: number | undefined;
30
+ }[], footnotesElementWithPos: NodeWithPos, position: number, inlineFootnoteIndex: number) => void;
@@ -18,6 +18,7 @@ import { Plugin, PluginKey } from 'prosemirror-state';
18
18
  interface PluginState {
19
19
  nodes: [InlineFootnoteNode, number][];
20
20
  labels: Map<string, string>;
21
+ tablesFootnoteLabels: Map<string, Map<string, number>>;
21
22
  }
22
23
  export declare const footnotesKey: PluginKey<PluginState>;
23
24
  export declare const buildPluginState: (doc: ManuscriptNode) => PluginState;
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": "1.7.23",
4
+ "version": "1.7.24-LEAN-3429-0",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -31,8 +31,8 @@
31
31
  "@manuscripts/assets": "^0.6.4",
32
32
  "@manuscripts/json-schema": "^2.2.6",
33
33
  "@manuscripts/library": "^1.3.5",
34
- "@manuscripts/style-guide": "^1.8.0",
35
- "@manuscripts/track-changes-plugin": "^1.7.7",
34
+ "@manuscripts/style-guide": "1.8.1-LEAN-3429-0",
35
+ "@manuscripts/track-changes-plugin": "1.7.8",
36
36
  "@manuscripts/transform": "^2.1.6",
37
37
  "astrocite-eutils": "^0.16.4",
38
38
  "axios": "^1.6.7",
@@ -109,6 +109,7 @@
109
109
  "uuid": "^9.0.0"
110
110
  },
111
111
  "resolutions": {
112
- "@types/react": "^17.0.2"
112
+ "@types/react": "^17.0.2",
113
+ "prosemirror-tables": "^1.3.5"
113
114
  }
114
- }
115
+ }