@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.
- package/dist/cjs/commands.js +12 -20
- package/dist/cjs/components/views/FootnotesSelector.js +4 -2
- package/dist/cjs/keys/misc.js +0 -1
- package/dist/cjs/lib/track-changes-utils.js +14 -46
- package/dist/cjs/plugins/footnotes/index.js +27 -129
- package/dist/cjs/plugins/footnotes/widgets.js +131 -0
- package/dist/cjs/plugins/{section_title/index.js → section_title.js} +1 -18
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/footnote.js +1 -0
- package/dist/cjs/views/inline_footnote.js +13 -7
- package/dist/es/commands.js +10 -17
- package/dist/es/components/views/FootnotesSelector.js +4 -2
- package/dist/es/keys/misc.js +2 -3
- package/dist/es/lib/track-changes-utils.js +13 -42
- package/dist/es/plugins/footnotes/index.js +23 -121
- package/dist/es/plugins/footnotes/widgets.js +122 -0
- package/dist/es/plugins/{section_title/index.js → section_title.js} +1 -18
- package/dist/es/versions.js +1 -1
- package/dist/es/views/footnote.js +1 -0
- package/dist/es/views/inline_footnote.js +14 -8
- package/dist/types/commands.d.ts +0 -1
- package/dist/types/lib/track-changes-utils.d.ts +1 -4
- package/dist/types/plugins/footnotes/index.d.ts +0 -1
- package/dist/types/plugins/footnotes/widgets.d.ts +22 -0
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/inline_footnote.d.ts +2 -6
- package/package.json +3 -3
- package/styles/AdvancedEditor.css +43 -62
- package/dist/cjs/lib/section-titles.js +0 -35
- package/dist/cjs/plugins/section_title/autocompletion.js +0 -45
- package/dist/es/lib/section-titles.js +0 -32
- package/dist/es/plugins/section_title/autocompletion.js +0 -40
- package/dist/types/lib/section-titles.d.ts +0 -17
- package/dist/types/plugins/section_title/autocompletion.d.ts +0 -10
- /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()).
|
|
92
|
-
node
|
|
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.
|
|
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
|
|
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;
|
package/dist/es/commands.js
CHANGED
|
@@ -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.
|
|
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 &&
|
|
92
|
+
const isNoteSelected = inlineFootnote &&
|
|
93
|
+
getActualAttrs(inlineFootnote).rids.includes(note.node.attrs.id);
|
|
92
94
|
if (isNoteSelected) {
|
|
93
95
|
selectedNotes.push(note);
|
|
94
96
|
}
|
package/dist/es/keys/misc.js
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { schema } from '@manuscripts/transform';
|
|
17
|
-
import { chainCommands,
|
|
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 {
|
|
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
|
|
81
|
-
|
|
82
|
-
|
|
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 {
|
|
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 {
|
|
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.
|
|
54
|
+
getActualAttrs(node).rids.forEach((rid) => {
|
|
154
55
|
labels.set(rid, getAlphaOrderIndices(index++));
|
|
155
56
|
});
|
|
156
57
|
});
|
|
157
58
|
const footnotesReordered = [];
|
|
158
|
-
const
|
|
59
|
+
const unusedFootnotes = new Map(footnotes);
|
|
159
60
|
inlineFootnotes.forEach(([node]) => {
|
|
160
61
|
const footnote = node;
|
|
161
|
-
footnote.
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
164
|
-
footnotesReordered.push(
|
|
165
|
-
|
|
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
|
|
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.
|
|
196
|
-
const newIds = inlineFootnoteNodes.map(([node]) => node.
|
|
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
|
|
106
|
+
const attrs = getActualAttrs(footnote);
|
|
107
|
+
const contents = attrs.rids
|
|
206
108
|
.map((rid) => {
|
|
207
|
-
const
|
|
208
|
-
if (
|
|
209
|
-
footnotesReordered.push(
|
|
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 (
|
|
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
|
|
220
|
-
if (
|
|
221
|
-
tr.replaceWith(footnoteElement[1], footnoteElement[1] + footnoteElement[0].nodeSize,
|
|
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 {
|
|
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);
|
package/dist/es/versions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '2.0.46
|
|
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()).
|
|
86
|
-
node
|
|
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.
|
|
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
|
|
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;
|
package/dist/types/commands.d.ts
CHANGED
|
@@ -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 {};
|