@manuscripts/body-editor 2.5.6-date-fix.0 → 2.5.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.
Files changed (88) hide show
  1. package/dist/cjs/commands.js +115 -205
  2. package/dist/cjs/components/views/DeleteFootnoteDialog.js +2 -2
  3. package/dist/cjs/components/views/FootnotesSelector.js +18 -19
  4. package/dist/cjs/configs/ManuscriptsEditor.js +2 -1
  5. package/dist/cjs/configs/editor-plugins.js +0 -2
  6. package/dist/cjs/configs/editor-views.js +6 -4
  7. package/dist/cjs/icons.js +8 -0
  8. package/dist/cjs/index.js +1 -0
  9. package/dist/cjs/lib/context-menu.js +21 -101
  10. package/dist/cjs/lib/doc.js +27 -4
  11. package/dist/cjs/lib/footnotes.js +31 -122
  12. package/dist/cjs/lib/plugins.js +8 -0
  13. package/dist/cjs/menus.js +1 -1
  14. package/dist/cjs/plugins/affiliations.js +2 -1
  15. package/dist/cjs/plugins/footnotes.js +188 -0
  16. package/dist/cjs/plugins/persist.js +4 -4
  17. package/dist/cjs/plugins/placeholder.js +19 -12
  18. package/dist/cjs/testing/default-editor-data.js +1 -1
  19. package/dist/cjs/testing/setup-editor.js +1 -0
  20. package/dist/cjs/versions.js +1 -1
  21. package/dist/cjs/views/editable_block.js +1 -1
  22. package/dist/cjs/views/footnote.js +117 -13
  23. package/dist/cjs/views/footnotes_element.js +10 -2
  24. package/dist/cjs/views/general_table_footnote.js +83 -0
  25. package/dist/cjs/views/inline_footnote.js +74 -124
  26. package/dist/cjs/views/table_element_footer.js +2 -5
  27. package/dist/es/commands.js +112 -201
  28. package/dist/es/components/views/DeleteFootnoteDialog.js +2 -2
  29. package/dist/es/components/views/FootnotesSelector.js +18 -19
  30. package/dist/es/configs/ManuscriptsEditor.js +2 -1
  31. package/dist/es/configs/editor-plugins.js +0 -2
  32. package/dist/es/configs/editor-views.js +4 -2
  33. package/dist/es/icons.js +5 -0
  34. package/dist/es/index.js +1 -0
  35. package/dist/es/lib/context-menu.js +24 -101
  36. package/dist/es/lib/doc.js +25 -4
  37. package/dist/es/lib/footnotes.js +28 -116
  38. package/dist/es/lib/plugins.js +4 -0
  39. package/dist/es/menus.js +1 -1
  40. package/dist/es/plugins/affiliations.js +2 -1
  41. package/dist/es/plugins/footnotes.js +185 -0
  42. package/dist/es/plugins/persist.js +4 -4
  43. package/dist/es/plugins/placeholder.js +20 -11
  44. package/dist/es/testing/default-editor-data.js +1 -1
  45. package/dist/es/testing/setup-editor.js +1 -0
  46. package/dist/es/versions.js +1 -1
  47. package/dist/es/views/editable_block.js +1 -1
  48. package/dist/es/views/footnote.js +118 -13
  49. package/dist/es/views/footnotes_element.js +10 -2
  50. package/dist/es/views/general_table_footnote.js +76 -0
  51. package/dist/es/views/inline_footnote.js +78 -128
  52. package/dist/es/views/table_element_footer.js +4 -5
  53. package/dist/types/commands.d.ts +10 -14
  54. package/dist/types/components/views/DeleteFootnoteDialog.d.ts +2 -2
  55. package/dist/types/components/views/FootnotesSelector.d.ts +7 -7
  56. package/dist/types/configs/editor-views.d.ts +22 -35
  57. package/dist/types/icons.d.ts +2 -0
  58. package/dist/types/index.d.ts +1 -0
  59. package/dist/types/lib/context-menu.d.ts +1 -3
  60. package/dist/types/lib/doc.d.ts +2 -0
  61. package/dist/types/lib/footnotes.d.ts +8 -19
  62. package/dist/types/lib/plugins.d.ts +3 -0
  63. package/dist/types/plugins/{footnotes/index.d.ts → footnotes.d.ts} +14 -11
  64. package/dist/types/plugins/placeholder.d.ts +0 -2
  65. package/dist/types/versions.d.ts +1 -1
  66. package/dist/types/views/footnote.d.ts +14 -6
  67. package/dist/types/views/footnotes_element.d.ts +1 -0
  68. package/dist/types/views/{table_element_footer_editable.d.ts → general_table_footnote.d.ts} +11 -2
  69. package/dist/types/views/inline_footnote.d.ts +8 -14
  70. package/dist/types/views/table_element_footer.d.ts +2 -2
  71. package/package.json +3 -3
  72. package/styles/Editor.css +35 -64
  73. package/dist/cjs/plugins/footnotes/index.js +0 -215
  74. package/dist/cjs/plugins/footnotes/widgets.js +0 -136
  75. package/dist/cjs/plugins/table-footnote.js +0 -46
  76. package/dist/cjs/views/footnote_editable.js +0 -21
  77. package/dist/cjs/views/footnotes_element_editable.js +0 -22
  78. package/dist/cjs/views/table_element_footer_editable.js +0 -20
  79. package/dist/es/plugins/footnotes/index.js +0 -211
  80. package/dist/es/plugins/footnotes/widgets.js +0 -127
  81. package/dist/es/plugins/table-footnote.js +0 -44
  82. package/dist/es/views/footnote_editable.js +0 -19
  83. package/dist/es/views/footnotes_element_editable.js +0 -20
  84. package/dist/es/views/table_element_footer_editable.js +0 -18
  85. package/dist/types/plugins/footnotes/widgets.d.ts +0 -22
  86. package/dist/types/plugins/table-footnote.d.ts +0 -3
  87. package/dist/types/views/footnote_editable.d.ts +0 -51
  88. package/dist/types/views/footnotes_element_editable.d.ts +0 -51
@@ -14,14 +14,10 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { getListType, isInBibliographySection, isSectionTitleNode, nodeNames, schema, } from '@manuscripts/transform';
17
- import { findChildrenByType, hasParentNodeOfType } from 'prosemirror-utils';
18
- import { addNodeComment, createBlock, findPosBeforeFirstSubsection, insertGeneralFootnote, insertTableFootnote, } from '../commands';
19
- import { FootnotesSelector } from '../components/views/FootnotesSelector';
20
- import ReactSubView from '../views/ReactSubView';
21
- import { buildTableFootnoteLabels } from './footnotes';
17
+ import { findChildrenByType } from 'prosemirror-utils';
18
+ import { addNodeComment, createBlock, findPosBeforeFirstSubsection, insertGeneralTableFootnote, insertInlineTableFootnote, } from '../commands';
22
19
  import { PopperManager } from './popper';
23
- import { isDeleted } from './track-changes-utils';
24
- import { getChildOfType, isChildOfNodeTypes, isSelectionInNode } from './utils';
20
+ import { isChildOfNodeTypes, isSelectionInNode } from './utils';
25
21
  const popper = new PopperManager();
26
22
  const readonlyTypes = [schema.nodes.keywords, schema.nodes.bibliography_element];
27
23
  const isBoxElementSectionTitle = ($pos, node) => isSectionTitleNode(node) &&
@@ -39,7 +35,7 @@ const hasAny = (set, ...items) => {
39
35
  };
40
36
  export const contextMenuBtnClass = 'btn-context-menu';
41
37
  export class ContextMenu {
42
- constructor(node, view, getPos, actions = {}, props) {
38
+ constructor(node, view, getPos, actions = {}) {
43
39
  this.showAddMenu = (target, after) => {
44
40
  const menu = document.createElement('div');
45
41
  menu.className = 'menu';
@@ -143,7 +139,6 @@ export class ContextMenu {
143
139
  this.addPopperEventListeners();
144
140
  };
145
141
  this.showEditMenu = (target) => {
146
- var _a;
147
142
  const menu = document.createElement('div');
148
143
  menu.className = 'menu';
149
144
  const $pos = this.resolvePos();
@@ -178,89 +173,23 @@ export class ContextMenu {
178
173
  }));
179
174
  }
180
175
  if (type === schema.nodes.table_element) {
181
- const isInTable = hasParentNodeOfType(schema.nodes.table)(this.view.state.selection);
182
- const tableElementFooter = findChildrenByType(this.node, schema.nodes.table_element_footer);
183
- let isDeletedInsert = false;
184
- const hasGeneralNote = tableElementFooter.length &&
185
- getChildOfType(tableElementFooter[0].node, schema.nodes.general_table_footnote, true);
186
- if (hasGeneralNote) {
187
- const generalFootnote = (_a = tableElementFooter[0]) === null || _a === void 0 ? void 0 : _a.node.firstChild;
188
- if (generalFootnote) {
189
- isDeletedInsert = isDeleted(generalFootnote);
190
- }
176
+ const items = [];
177
+ const isInsideNode = isSelectionInNode(this.view.state, this.node);
178
+ if (isInsideNode && insertInlineTableFootnote(this.view.state)) {
179
+ const item = this.createMenuItem('Add Reference Note', () => {
180
+ insertInlineTableFootnote(this.view.state, this.view.dispatch);
181
+ });
182
+ items.push(item);
191
183
  }
192
- if (!hasGeneralNote || isDeletedInsert) {
193
- menu.appendChild(this.createMenuSection((section) => {
194
- section.appendChild(this.createMenuItem('Add General Note', () => {
195
- insertGeneralFootnote(this.node, this.getPos(), this.view, tableElementFooter);
196
- }));
197
- }));
184
+ const pos = this.getPos();
185
+ if (insertGeneralTableFootnote([this.node, pos], this.view.state)) {
186
+ const item = this.createMenuItem('Add General Note', () => {
187
+ insertGeneralTableFootnote([this.node, pos], this.view.state, this.view.dispatch);
188
+ });
189
+ items.push(item);
198
190
  }
199
- if (isInTable) {
200
- const isInsideNode = isSelectionInNode(this.view.state, this.node);
201
- menu.appendChild(this.createMenuSection((section) => {
202
- section.appendChild(this.createMenuItem('Add Reference Note', () => {
203
- var _a;
204
- const footnotesElementWithPos = findChildrenByType(this.node, schema.nodes.footnotes_element).pop();
205
- if (!footnotesElementWithPos ||
206
- !(footnotesElementWithPos === null || footnotesElementWithPos === void 0 ? void 0 : footnotesElementWithPos.node.content.childCount) ||
207
- isDeleted(footnotesElementWithPos.node)) {
208
- insertTableFootnote(this.node, this.getPos(), this.view);
209
- }
210
- else {
211
- const tablesFootnoteLabels = buildTableFootnoteLabels(this.node);
212
- const footnotesWithPos = findChildrenByType(footnotesElementWithPos.node, schema.nodes.footnote);
213
- const footnotes = footnotesWithPos
214
- .filter(({ node }) => !isDeleted(node))
215
- .map(({ node }) => ({
216
- node: node,
217
- index: tablesFootnoteLabels.get(node.attrs.id),
218
- }));
219
- const targetDom = this.view.domAtPos(this.view.state.selection.from);
220
- const targetNode = targetDom.node.nodeType === Node.TEXT_NODE
221
- ? targetDom.node.parentNode
222
- : targetDom.node;
223
- if (targetNode instanceof Element && this.props) {
224
- const popperContainer = ReactSubView(Object.assign(Object.assign({}, this.props), { dispatch: this.view.dispatch }), FootnotesSelector, {
225
- notes: footnotes,
226
- onAdd: () => {
227
- var _a;
228
- insertTableFootnote(this.node, this.getPos(), this.view);
229
- (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
230
- },
231
- onInsert: (notes) => {
232
- var _a;
233
- const insertedAt = this.view.state.selection.to;
234
- let inlineFootnoteIndex = 1;
235
- this.view.state.doc
236
- .slice(this.getPos(), insertedAt)
237
- .content.descendants((node) => {
238
- if (node.type === schema.nodes.inline_footnote) {
239
- inlineFootnoteIndex++;
240
- return false;
241
- }
242
- });
243
- const node = this.view.state.schema.nodes.inline_footnote.create({
244
- rids: notes.map(({ node }) => node.attrs.id),
245
- contents: notes
246
- .map(({ index }) => index ? index : inlineFootnoteIndex)
247
- .join(),
248
- });
249
- const tr = this.view.state.tr;
250
- tr.insert(insertedAt, node);
251
- this.view.dispatch(tr);
252
- (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
253
- },
254
- onCancel: () => {
255
- var _a;
256
- (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.destroy();
257
- },
258
- }, this.node, this.getPos, this.view, 'footnote-editor');
259
- (_a = this.props) === null || _a === void 0 ? void 0 : _a.popper.show(targetNode, popperContainer, 'bottom-end');
260
- }
261
- }
262
- }, !isInsideNode));
263
- }));
191
+ if (items.length) {
192
+ menu.append(this.createMenuSection((e) => e.append(...items)));
264
193
  }
265
194
  }
266
195
  if (!readonlyTypes.includes(type) &&
@@ -279,19 +208,14 @@ export class ContextMenu {
279
208
  popper.show(target, menu, 'right', true);
280
209
  this.addPopperEventListeners();
281
210
  };
282
- this.createMenuItem = (contents, handler, isDisabled = false) => {
211
+ this.createMenuItem = (contents, handler) => {
283
212
  const item = document.createElement('div');
284
213
  item.className = 'menu-item';
285
214
  item.textContent = contents;
286
- if (isDisabled) {
287
- item.setAttribute('disabled', 'true');
288
- }
289
- else {
290
- item.addEventListener('mousedown', (event) => {
291
- event.preventDefault();
292
- handler(event);
293
- });
294
- }
215
+ item.addEventListener('mousedown', (event) => {
216
+ event.preventDefault();
217
+ handler(event);
218
+ });
295
219
  return item;
296
220
  };
297
221
  this.createMenuSection = (createMenuItems) => {
@@ -397,6 +321,5 @@ export class ContextMenu {
397
321
  this.view = view;
398
322
  this.getPos = getPos;
399
323
  this.actions = actions;
400
- this.props = props;
401
324
  }
402
325
  }
@@ -1,5 +1,5 @@
1
1
  import { schema, } from '@manuscripts/transform';
2
- import { findChildrenByType } from 'prosemirror-utils';
2
+ import { findChildren, findChildrenByType } from 'prosemirror-utils';
3
3
  export const insertSupplementsNode = (tr) => {
4
4
  const doc = tr.doc;
5
5
  const supplements = findChildrenByType(doc, schema.nodes.supplements)[0];
@@ -8,10 +8,27 @@ export const insertSupplementsNode = (tr) => {
8
8
  }
9
9
  const abstracts = findAbstractsNode(doc);
10
10
  const pos = abstracts.pos - 1;
11
- const supplementsNode = schema.nodes.supplements.createAndFill();
12
- tr.insert(pos, supplementsNode);
11
+ const node = schema.nodes.supplements.createAndFill();
12
+ tr.insert(pos, node);
13
13
  return {
14
- node: supplementsNode,
14
+ node,
15
+ pos,
16
+ };
17
+ };
18
+ export const insertFootnotesSection = (tr) => {
19
+ const doc = tr.doc;
20
+ const section = findChildrenByType(doc, schema.nodes.footnotes_section)[0];
21
+ if (section) {
22
+ return section;
23
+ }
24
+ const backmatter = findBackmatter(doc);
25
+ const pos = backmatter.pos + 1;
26
+ const node = schema.nodes.footnotes_section.create({}, [
27
+ schema.nodes.section_title.create({}, schema.text('Footnotes')),
28
+ ]);
29
+ tr.insert(pos, node);
30
+ return {
31
+ node,
15
32
  pos,
16
33
  };
17
34
  };
@@ -41,3 +58,7 @@ export const findGraphicalAbstractFigureElement = (doc) => {
41
58
  pos: ga.pos + element.pos + 1,
42
59
  };
43
60
  };
61
+ export const findNodeByID = (doc, id) => {
62
+ const children = findChildren(doc, (n) => n.attrs.id === id);
63
+ return children[0];
64
+ };
@@ -13,127 +13,39 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { skipTracking } from '@manuscripts/track-changes-plugin';
17
- import { isFootnoteNode, schema, } from '@manuscripts/transform';
18
- import { Fragment } from 'prosemirror-model';
19
- import { findChildren, findChildrenByType, findParentNodeClosestToPos, } from 'prosemirror-utils';
20
- export const findTableInlineFootnoteIds = ($pos) => {
21
- var _a;
22
- const tableElement = (_a = findParentNodeClosestToPos($pos, (node) => node.type === schema.nodes.table_element)) === null || _a === void 0 ? void 0 : _a.node;
23
- return new Set(tableElement
24
- ? findChildren(tableElement, (node) => node.type === schema.nodes.inline_footnote)
25
- .map(({ node }) => node.attrs.rids)
26
- .flat()
27
- : []);
28
- };
29
- export const getNewFootnotePos = (footnotesElement, footnoteIndex) => {
30
- let newFootnotePos = footnotesElement.pos + footnotesElement.node.nodeSize - 1;
31
- footnotesElement.node.descendants((node, pos, parent, index) => {
32
- if (isFootnoteNode(node)) {
33
- if (footnoteIndex === ++index) {
34
- newFootnotePos = footnotesElement.pos + pos + (index === 1 ? 2 : 1);
35
- }
36
- }
37
- });
38
- return newFootnotePos;
39
- };
40
- export const buildTableFootnoteLabels = (node) => {
41
- const labels = new Map(findChildrenByType(node, schema.nodes.footnote).map((node) => [
42
- node.node.attrs.id,
43
- undefined,
44
- ]));
45
- let index = 0;
46
- findChildrenByType(node, schema.nodes.inline_footnote)
47
- .map(({ node }) => node.attrs.rids)
48
- .flat()
49
- .map((rid) => {
50
- if (!labels.get(rid)) {
51
- labels.set(rid, String(++index));
52
- }
16
+ import { generateNodeID, schema, } from '@manuscripts/transform';
17
+ import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, } from 'prosemirror-utils';
18
+ import { footnotesKey } from '../plugins/footnotes';
19
+ export const findFootnotesContainerNode = (doc, pos) => {
20
+ const $pos = doc.resolve(pos);
21
+ return (findParentNodeOfTypeClosestToPos($pos, schema.nodes.table_element) || {
22
+ node: doc,
23
+ pos: 0,
53
24
  });
54
- return labels;
55
25
  };
56
- export const orderTableFootnotes = (tr, footnotesElementWithPos, position) => {
57
- const tablesFootnoteLabels = buildTableFootnoteLabels(tr.doc.nodeAt(tr.mapping.map(position)));
58
- const footnotes = findChildrenByType(footnotesElementWithPos.node, schema.nodes.footnote).map((nodeWithPos) => ({
59
- node: nodeWithPos.node,
60
- index: tablesFootnoteLabels.get(nodeWithPos.node.attrs.id),
61
- }));
62
- const orderedFootnotes = [...footnotes]
63
- .sort((a, b) => {
64
- if (a.index !== undefined && b.index !== undefined) {
65
- return Number.parseInt(a.index) - Number.parseInt(b.index);
66
- }
67
- else {
68
- return a.index === undefined ? 1 : -1;
69
- }
70
- })
71
- .map(({ node }) => node);
72
- const { node: footnotesElement, pos } = footnotesElementWithPos;
73
- const footnoteElementPos = position + pos + 1;
74
- if (orderedFootnotes.length === 0) {
26
+ export const findParentFootnote = findParentNodeOfType([
27
+ schema.nodes.footnote,
28
+ schema.nodes.general_table_footnote,
29
+ ]);
30
+ export const getFootnotesElementState = (state, id) => {
31
+ const fns = footnotesKey.getState(state);
32
+ if (!fns) {
75
33
  return;
76
34
  }
77
- const oldDataTracked = footnotesElement.attrs.dataTracked;
78
- skipTracking(tr.replaceWith(tr.mapping.map(footnoteElementPos), tr.mapping.map(footnoteElementPos + footnotesElement.nodeSize), Fragment.fromArray(orderedFootnotes)));
79
- if (oldDataTracked) {
80
- tr.setNodeMarkup(footnoteElementPos, schema.nodes.footnotes_element, Object.assign(Object.assign({}, footnotesElement.attrs), { dataTracked: oldDataTracked }));
35
+ const elementID = fns.footnotesElementIDs.get(id);
36
+ if (!elementID) {
37
+ return;
81
38
  }
39
+ return fns.footnotesElements.get(elementID);
82
40
  };
83
- export const updateTableInlineFootnoteLabels = (tr, table) => {
84
- const labels = buildTableFootnoteLabels(table.node);
85
- findChildrenByType(table.node, schema.nodes.inline_footnote).map(({ node, pos }) => {
86
- const contents = node.attrs.rids
87
- .map((rid) => labels.get(rid))
88
- .join(',');
89
- if (contents !== node.attrs.contents &&
90
- tr.doc.nodeAt(tr.mapping.map(table.pos + pos + 1))) {
91
- tr.setNodeMarkup(tr.mapping.map(table.pos + pos + 1), undefined, Object.assign(Object.assign({}, node.attrs), { rids: node.attrs.rids, contents }));
92
- }
93
- });
94
- return tr;
41
+ export const getFootnoteLabel = (state, footnote) => {
42
+ const id = footnote.attrs.id;
43
+ const fns = getFootnotesElementState(state, id);
44
+ return (fns === null || fns === void 0 ? void 0 : fns.labels.get(id)) || '';
95
45
  };
96
- export const getInlineFootnotes = (id, targetNode) => {
97
- const inlineFootnotes = [];
98
- targetNode.descendants((node, pos) => {
99
- var _a;
100
- if (node.type === schema.nodes.inline_footnote) {
101
- const footnote = node;
102
- if ((_a = footnote.attrs.rids) === null || _a === void 0 ? void 0 : _a.includes(id)) {
103
- inlineFootnotes.push({ node: footnote, pos });
104
- }
105
- }
106
- });
107
- return inlineFootnotes;
46
+ export const createFootnote = () => {
47
+ return schema.nodes.footnote.createAndFill({
48
+ id: generateNodeID(schema.nodes.footnote),
49
+ kind: 'footnote',
50
+ }, [schema.nodes.paragraph.create({})]);
108
51
  };
109
- export function getAlphaOrderIndices(index) {
110
- const unicodeInterval = [97, 123];
111
- const places = unicodeInterval[1] - unicodeInterval[0];
112
- function getClassCount(n, order) {
113
- return n * Math.pow(places, order - 1);
114
- }
115
- let indices = null;
116
- for (;;) {
117
- let current = index;
118
- let position = 1;
119
- while (current >= places) {
120
- current = current / places;
121
- position++;
122
- }
123
- const newIndex = Math.floor(current);
124
- indices = indices ? indices : new Array(position).fill(0);
125
- indices.splice(indices.length - position, 1, newIndex);
126
- index -= getClassCount(newIndex, position);
127
- if (position === 1) {
128
- break;
129
- }
130
- }
131
- return (indices || [])
132
- .map((v, i, array) => {
133
- if (array.length > 1 && i !== array.length - 1) {
134
- return String.fromCodePoint(v + unicodeInterval[0] - 1);
135
- }
136
- return String.fromCodePoint(v + unicodeInterval[0]);
137
- })
138
- .join('');
139
- }
@@ -0,0 +1,4 @@
1
+ export const INIT_META = 'INIT';
2
+ export const isInit = (tr) => {
3
+ return tr.getMeta(INIT_META);
4
+ };
package/dist/es/menus.js CHANGED
@@ -298,7 +298,7 @@ export const getEditorMenus = (editor) => {
298
298
  pc: 'CommandOrControl+Option+F',
299
299
  },
300
300
  isEnabled: isCommandValid(canInsert(schema.nodes.inline_footnote)),
301
- run: doCommand(insertInlineFootnote('footnote')),
301
+ run: doCommand(insertInlineFootnote),
302
302
  },
303
303
  {
304
304
  id: 'insert-comment',
@@ -18,6 +18,7 @@ import { isEqual } from 'lodash';
18
18
  import { Plugin, PluginKey } from 'prosemirror-state';
19
19
  import { Decoration, DecorationSet } from 'prosemirror-view';
20
20
  import { authorComparator, } from '../lib/authors';
21
+ import { isInit } from '../lib/plugins';
21
22
  import { isDeleted, isPendingInsert } from '../lib/track-changes-utils';
22
23
  export const affiliationsKey = new PluginKey('affiliations');
23
24
  let id = 1;
@@ -84,7 +85,7 @@ export default () => {
84
85
  },
85
86
  appendTransaction(transactions, oldState, newState) {
86
87
  const affs = affiliationsKey.getState(newState);
87
- if (!affs || !transactions.find((tr) => tr.docChanged)) {
88
+ if (!affs || !transactions.find((tr) => tr.docChanged || isInit(tr))) {
88
89
  return;
89
90
  }
90
91
  const $old = affiliationsKey.getState(oldState);
@@ -0,0 +1,185 @@
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 { skipTracking } from '@manuscripts/track-changes-plugin';
17
+ import { generateAlphaFootnoteLabel, isTableElementNode, schema, } from '@manuscripts/transform';
18
+ import { isEqual } from 'lodash';
19
+ import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
20
+ import { findChildrenByType } from 'prosemirror-utils';
21
+ import { Decoration, DecorationSet } from 'prosemirror-view';
22
+ import { findNodeByID } from '../lib/doc';
23
+ import { findFootnotesContainerNode, findParentFootnote, } from '../lib/footnotes';
24
+ import { isInit } from '../lib/plugins';
25
+ export const footnotesKey = new PluginKey('footnotes');
26
+ const buildPluginState = (doc) => {
27
+ const states = new Map();
28
+ const ids = new Map();
29
+ const elements = findChildrenByType(doc, schema.nodes.footnotes_element);
30
+ elements.map(({ node, pos }) => {
31
+ const container = findFootnotesContainerNode(doc, pos);
32
+ const newState = buildFootnotesElementState([container.node, container.pos], [node, pos]);
33
+ const elementID = node.attrs.id;
34
+ states.set(elementID, newState);
35
+ newState.footnotes.forEach(([n]) => ids.set(n.attrs.id, elementID));
36
+ newState.inlineFootnotes.forEach(([n]) => ids.set(n.attrs.id, elementID));
37
+ ids.set(container.node.attrs.id, elementID);
38
+ });
39
+ return {
40
+ footnotesElements: states,
41
+ footnotesElementIDs: ids,
42
+ };
43
+ };
44
+ const buildFootnotesElementState = (container, element) => {
45
+ const fn = {
46
+ element,
47
+ inlineFootnotes: [],
48
+ unusedFootnoteIDs: new Set(),
49
+ footnotes: [],
50
+ labels: new Map(),
51
+ };
52
+ const footnotes = findChildrenByType(element[0], schema.nodes.footnote);
53
+ const footnoteIDs = new Set();
54
+ footnotes.forEach(({ node, pos }) => {
55
+ fn.footnotes.push([node, element[1] + pos + 1]);
56
+ fn.unusedFootnoteIDs.add(node.attrs.id);
57
+ footnoteIDs.add(node.attrs.id);
58
+ });
59
+ let index = 0;
60
+ const inlineFootnotes = findChildrenByType(container[0], schema.nodes.inline_footnote);
61
+ inlineFootnotes.sort((a, b) => a.pos - b.pos);
62
+ const orderedFootnoteIDs = [];
63
+ inlineFootnotes.forEach(({ node, pos }) => {
64
+ const inlineFootnote = node;
65
+ const rids = inlineFootnote.attrs.rids;
66
+ if (rids.some((rid) => !footnoteIDs.has(rid))) {
67
+ return;
68
+ }
69
+ if (container[1]) {
70
+ pos += container[1] + 1;
71
+ }
72
+ fn.inlineFootnotes.push([node, pos]);
73
+ const label = rids
74
+ .map((rid) => {
75
+ if (fn.labels.has(rid)) {
76
+ return fn.labels.get(rid);
77
+ }
78
+ else {
79
+ const label = isTableElementNode(container[0])
80
+ ? String(++index)
81
+ : generateAlphaFootnoteLabel(index++);
82
+ fn.labels.set(rid, label);
83
+ fn.unusedFootnoteIDs.delete(rid);
84
+ orderedFootnoteIDs.push(rid);
85
+ return label;
86
+ }
87
+ })
88
+ .join(', ');
89
+ fn.labels.set(node.attrs.id, label);
90
+ });
91
+ fn.unusedFootnoteIDs.forEach((id) => orderedFootnoteIDs.push(id));
92
+ fn.footnotes.sort(([a], [b]) => orderedFootnoteIDs.indexOf(a.attrs.id) -
93
+ orderedFootnoteIDs.indexOf(b.attrs.id));
94
+ return fn;
95
+ };
96
+ const hasChanged = ($new, $old) => {
97
+ const nids = $new.footnotes.map(([node]) => node.attrs.id);
98
+ const oids = $old === null || $old === void 0 ? void 0 : $old.footnotes.map(([node]) => node.attrs.id);
99
+ return !(isEqual(nids, oids) &&
100
+ isEqual($new.unusedFootnoteIDs, $old === null || $old === void 0 ? void 0 : $old.unusedFootnoteIDs));
101
+ };
102
+ export default (props) => {
103
+ return new Plugin({
104
+ key: footnotesKey,
105
+ state: {
106
+ init(config, instance) {
107
+ return buildPluginState(instance.doc);
108
+ },
109
+ apply(tr, value, oldState, newState) {
110
+ const $old = footnotesKey.getState(oldState);
111
+ if (!tr.docChanged && $old) {
112
+ return $old;
113
+ }
114
+ return buildPluginState(newState.doc);
115
+ },
116
+ },
117
+ appendTransaction(transactions, oldState, newState) {
118
+ var _a;
119
+ if (!transactions.find((tr) => tr.docChanged || isInit(tr))) {
120
+ return;
121
+ }
122
+ const $old = footnotesKey.getState(oldState);
123
+ const $new = footnotesKey.getState(newState);
124
+ if (!$new) {
125
+ return;
126
+ }
127
+ const tr = newState.tr;
128
+ $new.footnotesElements.forEach((newState, key) => {
129
+ const element = newState.element[0];
130
+ const pos = newState.element[1];
131
+ const oldState = $old === null || $old === void 0 ? void 0 : $old.footnotesElements.get(key);
132
+ const footnotes = newState.footnotes.map(([node]) => node);
133
+ if (hasChanged(newState, oldState)) {
134
+ const newElement = schema.nodes.footnotes_element.create(element.attrs, footnotes);
135
+ tr.replaceWith(pos, pos + element.nodeSize, newElement);
136
+ }
137
+ });
138
+ if (!tr.steps.length) {
139
+ return;
140
+ }
141
+ const selection = newState.selection;
142
+ const selectedFootnote = findParentFootnote(selection);
143
+ if (selectedFootnote) {
144
+ const pos = (_a = findNodeByID(tr.doc, selectedFootnote.node.attrs.id)) === null || _a === void 0 ? void 0 : _a.pos;
145
+ if (pos) {
146
+ tr.setSelection(TextSelection.create(tr.doc, pos + 2));
147
+ }
148
+ }
149
+ skipTracking(tr);
150
+ return tr;
151
+ },
152
+ props: {
153
+ decorations: (state) => {
154
+ const fns = footnotesKey.getState(state);
155
+ if (!fns) {
156
+ return DecorationSet.empty;
157
+ }
158
+ const decorations = [];
159
+ fns.footnotesElements.forEach((fn) => {
160
+ fn.footnotes.forEach(([node, pos]) => {
161
+ const to = pos + node.nodeSize;
162
+ const label = fn.labels.get(node.attrs.id);
163
+ decorations.push(Decoration.node(pos, to, {}, { label }));
164
+ });
165
+ fn.inlineFootnotes.forEach(([node, pos]) => {
166
+ const to = pos + node.nodeSize;
167
+ const label = fn.labels.get(node.attrs.id);
168
+ decorations.push(Decoration.node(pos, to, {}, { label }));
169
+ });
170
+ });
171
+ if (props.getCapabilities().editArticle) {
172
+ const footnote = findParentFootnote(state.selection);
173
+ if (footnote) {
174
+ const pos = footnote.pos;
175
+ const to = pos + footnote.node.nodeSize;
176
+ decorations.push(Decoration.node(pos, to, {
177
+ class: 'footnote-selected',
178
+ }));
179
+ }
180
+ }
181
+ return DecorationSet.create(state.doc, decorations);
182
+ },
183
+ },
184
+ });
185
+ };
@@ -1,20 +1,20 @@
1
1
  import { skipTracking } from '@manuscripts/track-changes-plugin';
2
2
  import { generateNodeID, schema } from '@manuscripts/transform';
3
3
  import { Plugin } from 'prosemirror-state';
4
+ import { isInit } from '../lib/plugins';
4
5
  const isManuscriptNode = (node) => {
5
6
  return node && node.type === schema.nodes.manuscript;
6
7
  };
7
8
  export default () => {
8
9
  return new Plugin({
9
10
  appendTransaction(transactions, oldState, newState) {
10
- if (!transactions.some((tr) => tr.docChanged)) {
11
+ if (!transactions.some((tr) => tr.docChanged || isInit(tr))) {
11
12
  return null;
12
13
  }
13
14
  const ids = new Set();
14
15
  const tr = newState.tr;
15
16
  newState.doc.descendants((node, pos, parent) => {
16
- if (node.isInline ||
17
- isManuscriptNode(node) ||
17
+ if (isManuscriptNode(node) ||
18
18
  isManuscriptNode(parent) ||
19
19
  !node.type.spec.attrs ||
20
20
  !('id' in node.type.spec.attrs)) {
@@ -23,7 +23,7 @@ export default () => {
23
23
  let id = node.attrs.id;
24
24
  if (!id || ids.has(id)) {
25
25
  id = generateNodeID(node.type);
26
- tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, node.attrs), { id }), node.marks);
26
+ tr.setNodeAttribute(pos, 'id', id);
27
27
  }
28
28
  ids.add(id);
29
29
  });