@manuscripts/body-editor 1.7.25 → 1.7.26-LEAN-3143-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.
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.alertIcon = exports.editAttrsTrackingIcon = exports.commentIcon = exports.editIcon = void 0;
18
+ exports.deleteIcon = exports.alertIcon = exports.editAttrsTrackingIcon = exports.commentIcon = exports.editIcon = void 0;
19
19
  exports.editIcon = `
20
20
  <svg
21
21
  width="14"
@@ -118,3 +118,49 @@ exports.alertIcon = `
118
118
  />
119
119
  </svg>
120
120
  `;
121
+ exports.deleteIcon = `
122
+ <svg
123
+ width="13"
124
+ height="15"
125
+ viewBox="0 0 13 15"
126
+ fill="none"
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ >
129
+ <path
130
+ fill-rule="evenodd"
131
+ clip-rule="evenodd"
132
+ d="M2.00001 3C2 3.00135 2 3.00269 2 3.00404V13.004C2 13.5563 2.44772 14.004 3 14.004H10C10.5523 14.004 11 13.5563 11 13.004V3.00404C11 3.00269 11 3.00135 11 3C11.5978 3.34581 12 3.99215 12 4.73244V13.004C12 14.1086 11.1046 15.004 10 15.004H3C1.89543 15.004 1 14.1086 1 13.004V4.73244C1 3.99215 1.4022 3.34581 2.00001 3Z"
133
+ fill="#C9C9C9"
134
+ />
135
+ <path
136
+ fill-rule="evenodd"
137
+ clip-rule="evenodd"
138
+ d="M4.5 0C3.67157 0 3 0.671573 3 1.5V3.5C3 4.32843 3.67157 5 4.5 5H8.5C9.32843 5 10 4.32843 10 3.5V1.5C10 0.671573 9.32843 0 8.5 0H4.5ZM9 1.5C9 1.22386 8.77614 1 8.5 1H4.5C4.22386 1 4 1.22386 4 1.5C4 1.77614 4.22386 2 4.5 2H8.5C8.77614 2 9 1.77614 9 1.5Z"
139
+ fill="#C9C9C9"
140
+ />
141
+ <rect
142
+ y="2"
143
+ width="13"
144
+ height="3"
145
+ rx="1.5"
146
+ fill="#C9C9C9"
147
+ />
148
+ <path
149
+ fill-rule="evenodd"
150
+ clip-rule="evenodd"
151
+ d="M8 7.5C8 7.22386 8.22386 7 8.5 7C8.77614 7 9 7.22386 9 7.5V11.5C9 11.7761 8.77614 12 8.5 12C8.22386 12 8 11.7761 8 11.5V7.5Z"
152
+ fill="#C9C9C9"
153
+ />
154
+ <path
155
+ fill-rule="evenodd"
156
+ clip-rule="evenodd"
157
+ d="M4 7.5C4 7.22386 4.22386 7 4.5 7C4.77614 7 5 7.22386 5 7.5V11.5C5 11.7761 4.77614 12 4.5 12C4.22386 12 4 11.7761 4 11.5V7.5Z"
158
+ fill="#C9C9C9"
159
+ />
160
+ <path
161
+ fill-rule="evenodd"
162
+ clip-rule="evenodd"
163
+ d="M11.5 3C11.7761 3 12 3.22386 12 3.5C12 3.77614 11.7761 4 11.5 4L1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3L11.5 3Z"
164
+ fill="white"
165
+ />
166
+ </svg>`;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.DeleteFootnoteDialog = void 0;
27
+ const style_guide_1 = require("@manuscripts/style-guide");
28
+ const react_1 = __importStar(require("react"));
29
+ const DeleteFootnoteDialog = ({ footnoteType, footnoteMessage, handleDelete, }) => {
30
+ const [isOpen, setOpen] = (0, react_1.useState)(true);
31
+ return (react_1.default.createElement(style_guide_1.Dialog, { isOpen: isOpen, actions: {
32
+ primary: {
33
+ action: () => setOpen(false),
34
+ title: 'Cancel',
35
+ },
36
+ secondary: {
37
+ action: () => {
38
+ setOpen(false);
39
+ handleDelete();
40
+ },
41
+ title: 'Delete',
42
+ },
43
+ }, category: style_guide_1.Category.confirmation, header: `Delete ${footnoteType}`, message: `${footnoteMessage}` }));
44
+ };
45
+ exports.DeleteFootnoteDialog = DeleteFootnoteDialog;
@@ -68,7 +68,7 @@ exports.default = (props) => {
68
68
  (0, prosemirror_tables_1.tableEditing)(),
69
69
  (0, highlight_1.default)(props),
70
70
  (0, selected_suggestion_ui_1.default)(props),
71
- (0, footnotes_1.default)(),
71
+ (0, footnotes_1.default)(props),
72
72
  ];
73
73
  if (props.collabProvider) {
74
74
  allPlugins.push((0, prosemirror_collab_1.collab)({ version: props.collabProvider.currentVersion }));
@@ -14,6 +14,9 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
17
20
  Object.defineProperty(exports, "__esModule", { value: true });
18
21
  exports.uncitedFootnoteWidget = exports.buildPluginState = exports.footnotesKey = void 0;
19
22
  const transform_1 = require("@manuscripts/transform");
@@ -22,7 +25,10 @@ const prosemirror_state_1 = require("prosemirror-state");
22
25
  const prosemirror_utils_1 = require("prosemirror-utils");
23
26
  const prosemirror_view_1 = require("prosemirror-view");
24
27
  const assets_1 = require("../../assets");
28
+ const DeleteFootnoteDialog_1 = require("../../components/views/DeleteFootnoteDialog");
29
+ const track_changes_utils_1 = require("../../lib/track-changes-utils");
25
30
  const utils_1 = require("../../lib/utils");
31
+ const ReactSubView_1 = __importDefault(require("../../views/ReactSubView"));
26
32
  const placeholder_1 = require("../placeholder");
27
33
  const footnotes_utils_1 = require("./footnotes-utils");
28
34
  exports.footnotesKey = new prosemirror_state_1.PluginKey('footnotes');
@@ -68,7 +74,60 @@ const uncitedFootnoteWidget = () => () => {
68
74
  return element;
69
75
  };
70
76
  exports.uncitedFootnoteWidget = uncitedFootnoteWidget;
71
- exports.default = () => {
77
+ const getInlineFootnote = (view, id) => {
78
+ let inlineFootnote = null;
79
+ let footnotePosition = null;
80
+ view.state.doc.descendants((node, pos) => {
81
+ var _a;
82
+ const footnote = node;
83
+ if ((_a = footnote.attrs.rids) === null || _a === void 0 ? void 0 : _a.includes(id)) {
84
+ inlineFootnote = footnote;
85
+ footnotePosition = pos;
86
+ return false;
87
+ }
88
+ });
89
+ return { node: inlineFootnote, pos: footnotePosition };
90
+ };
91
+ const deleteFootnoteWidget = (node, pos, props, footnoteType, footnoteMessage, id) => (view) => {
92
+ const deleteBtn = document.createElement('span');
93
+ deleteBtn.className = 'delete-icon';
94
+ deleteBtn.innerHTML = assets_1.deleteIcon;
95
+ deleteBtn.addEventListener('click', () => {
96
+ const handleDelete = () => {
97
+ const tr = view.state.tr;
98
+ if (node.type === transform_1.schema.nodes.table_element_footer) {
99
+ node.content.forEach((item) => {
100
+ if (item.type === transform_1.schema.nodes.paragraph) {
101
+ tr.delete(pos, pos + item.nodeSize + 1);
102
+ }
103
+ });
104
+ if (!node.childCount) {
105
+ tr.setSelection(prosemirror_state_1.TextSelection.near(view.state.doc.resolve(0))).delete(pos, pos + node.nodeSize + 1);
106
+ }
107
+ }
108
+ if (node.type === transform_1.schema.nodes.footnote) {
109
+ const inlineFootnotes = getInlineFootnote(view, id);
110
+ tr.setSelection(prosemirror_state_1.TextSelection.near(view.state.doc.resolve(0))).delete(pos, pos + node.nodeSize + 1);
111
+ if (inlineFootnotes.node) {
112
+ const pos = inlineFootnotes.pos;
113
+ const nodeSize = inlineFootnotes.node.nodeSize;
114
+ if (pos && nodeSize) {
115
+ tr.delete(pos, pos + nodeSize);
116
+ }
117
+ }
118
+ }
119
+ view.dispatch(tr);
120
+ };
121
+ const componentProps = {
122
+ footnoteType: footnoteType,
123
+ footnoteMessage: footnoteMessage,
124
+ handleDelete: handleDelete,
125
+ };
126
+ (0, ReactSubView_1.default)(Object.assign(Object.assign({}, props), { dispatch: view.dispatch }), DeleteFootnoteDialog_1.DeleteFootnoteDialog, componentProps, node, () => pos, view);
127
+ });
128
+ return deleteBtn;
129
+ };
130
+ exports.default = (props) => {
72
131
  return new prosemirror_state_1.Plugin({
73
132
  key: exports.footnotesKey,
74
133
  state: {
@@ -101,6 +160,7 @@ exports.default = () => {
101
160
  decorations: (state) => {
102
161
  const decorations = [];
103
162
  const isInTableElementFooter = (0, prosemirror_utils_1.hasParentNodeOfType)(transform_1.schema.nodes.table_element_footer)(state.selection);
163
+ const isInTableElement = (0, prosemirror_utils_1.hasParentNodeOfType)(transform_1.schema.nodes.table_element)(state.selection);
104
164
  if (isInTableElementFooter) {
105
165
  const parent = (0, utils_1.findParentNodeWithIdValue)(state.selection);
106
166
  if (parent) {
@@ -131,6 +191,40 @@ exports.default = () => {
131
191
  decorations.push(prosemirror_view_1.Decoration.widget(pos + node.nodeSize - 1, (0, exports.uncitedFootnoteWidget)()));
132
192
  }
133
193
  }
194
+ if (isInTableElement) {
195
+ const isGeneralFootnote = node.type === transform_1.schema.nodes.paragraph;
196
+ const isTableFootnote = node.type === transform_1.schema.nodes.footnote;
197
+ const footnote = (() => {
198
+ switch (node.type) {
199
+ case transform_1.schema.nodes.footnote:
200
+ return {
201
+ type: 'table footnote',
202
+ message: 'This action will entirely remove the table footnote from the list because it will no longer be used.',
203
+ };
204
+ default:
205
+ return {
206
+ type: 'table general note',
207
+ message: 'This action will entirely remove the table general note.',
208
+ };
209
+ }
210
+ })();
211
+ if (isTableFootnote) {
212
+ decorations.push(prosemirror_view_1.Decoration.widget(pos + 2, deleteFootnoteWidget(node, pos, props, footnote.type, footnote.message, node.attrs.id), {
213
+ key: node.attrs.id,
214
+ }));
215
+ }
216
+ else if (isGeneralFootnote &&
217
+ (parent === null || parent === void 0 ? void 0 : parent.type) === transform_1.schema.nodes.table_element_footer) {
218
+ decorations.push(prosemirror_view_1.Decoration.widget(pos + 2, deleteFootnoteWidget(parent, pos, props, footnote.type, footnote.message, parent.attrs.id), {
219
+ key: parent.attrs.id,
220
+ }));
221
+ }
222
+ if ((0, track_changes_utils_1.isDeleted)(node)) {
223
+ decorations.push(prosemirror_view_1.Decoration.node(pos, pos + node.nodeSize, {
224
+ class: 'deleted-footnote',
225
+ }));
226
+ }
227
+ }
134
228
  if (node.type === transform_1.schema.nodes.footnotes_element) {
135
229
  if ((parent === null || parent === void 0 ? void 0 : parent.type) === transform_1.schema.nodes.table_element_footer) {
136
230
  decorations.push(prosemirror_view_1.Decoration.node(pos, pos + node.nodeSize, {
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.selectedSuggestionKey = exports.SET_SUGGESTION_ID = void 0;
18
+ exports.selectedSuggestionKey = exports.CLEAR_SUGGESTION_ID = exports.SET_SUGGESTION_ID = void 0;
19
19
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
20
20
  const lodash_1 = require("lodash");
21
21
  const prosemirror_state_1 = require("prosemirror-state");
@@ -81,7 +81,7 @@ const getTrackChangesData = (node) => {
81
81
  return (_a = trackChangesMark === null || trackChangesMark === void 0 ? void 0 : trackChangesMark.attrs) === null || _a === void 0 ? void 0 : _a.dataTracked;
82
82
  };
83
83
  exports.SET_SUGGESTION_ID = 'SET_SELECTED_SUGGESTION_ID';
84
- const CLEAR_SUGGESTION_ID = 'CLEAR_SUGGESTION_ID';
84
+ exports.CLEAR_SUGGESTION_ID = 'CLEAR_SUGGESTION_ID';
85
85
  exports.selectedSuggestionKey = new prosemirror_state_1.PluginKey('selected_suggestion');
86
86
  exports.default = (props) => new prosemirror_state_1.Plugin({
87
87
  key: exports.selectedSuggestionKey,
@@ -93,7 +93,7 @@ exports.default = (props) => new prosemirror_state_1.Plugin({
93
93
  if (suggestionId) {
94
94
  return buildSelectedSuggestionDecoration(suggestionId, state, props);
95
95
  }
96
- if (tr.getMeta(CLEAR_SUGGESTION_ID)) {
96
+ if (tr.getMeta(exports.CLEAR_SUGGESTION_ID)) {
97
97
  props.setEditorSelectedSuggestion(undefined);
98
98
  return prosemirror_view_1.DecorationSet.empty;
99
99
  }
@@ -105,7 +105,7 @@ exports.default = (props) => new prosemirror_state_1.Plugin({
105
105
  const nodeClicked = view.state.doc.nodeAt(pos);
106
106
  const trackChangesData = nodeClicked && getTrackChangesData(nodeClicked);
107
107
  if (!trackChangesData) {
108
- view.dispatch(view.state.tr.setMeta(CLEAR_SUGGESTION_ID, true));
108
+ view.dispatch(view.state.tr.setMeta(exports.CLEAR_SUGGESTION_ID, true));
109
109
  props.setEditorSelectedSuggestion(undefined);
110
110
  }
111
111
  },
@@ -28,9 +28,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
30
  exports.BibliographyElementBlockView = void 0;
31
+ const style_guide_1 = require("@manuscripts/style-guide");
31
32
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
32
33
  const transform_1 = require("@manuscripts/transform");
33
- const assets_1 = require("../assets");
34
34
  const dompurify_1 = require("../lib/dompurify");
35
35
  const track_changes_utils_1 = require("../lib/track-changes-utils");
36
36
  const view_1 = require("../lib/view");
@@ -45,8 +45,9 @@ class BibliographyElementBlockView extends block_view_1.default {
45
45
  constructor() {
46
46
  super(...arguments);
47
47
  this.decoder = new transform_1.Decoder(new Map());
48
- this.gutterButtons = () => [];
48
+ this.clickedElementId = null;
49
49
  this.showPopper = (id) => {
50
+ this.props.popper.destroy();
50
51
  const bib = (0, bibliography_1.getBibliographyPluginState)(this.view.state);
51
52
  const componentProps = {
52
53
  items: Array.from(bib.bibliographyItems.values()),
@@ -60,6 +61,52 @@ class BibliographyElementBlockView extends block_view_1.default {
60
61
  };
61
62
  this.stopEvent = () => true;
62
63
  this.ignoreMutation = () => true;
64
+ this.handleEdit = (citationId) => {
65
+ this.showPopper(citationId);
66
+ };
67
+ this.handleComment = (citationId) => {
68
+ this.props.setComment((0, transform_1.buildComment)(citationId));
69
+ };
70
+ this.showContextMenu = (elementId) => {
71
+ this.props.popper.destroy();
72
+ this.clickedElementId = null;
73
+ const can = this.props.getCapabilities();
74
+ const element = document.getElementById(elementId);
75
+ const componentProps = {
76
+ actions: [],
77
+ };
78
+ if (can.editCitationsAndRefs) {
79
+ componentProps.actions.push({
80
+ label: 'Edit',
81
+ action: () => this.handleEdit(elementId),
82
+ icon: 'EditIcon',
83
+ });
84
+ }
85
+ componentProps.actions.push({
86
+ label: 'Comment',
87
+ action: () => this.handleComment(elementId),
88
+ icon: 'AddComment',
89
+ });
90
+ this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu');
91
+ this.props.popper.show(element, this.contextMenu, 'right-start');
92
+ };
93
+ this.onClickHandler = (elementId, dataTracked) => {
94
+ var _a;
95
+ this.clickedElementId = elementId;
96
+ const isSelectedSuggestion = !!((_a = selected_suggestion_ui_1.selectedSuggestionKey
97
+ .getState(this.view.state)) === null || _a === void 0 ? void 0 : _a.find(this.getPos(), this.getPos() + this.node.nodeSize).length);
98
+ if (dataTracked && dataTracked.status !== track_changes_plugin_1.CHANGE_STATUS.rejected) {
99
+ this.view.dispatch(this.view.state.tr.setMeta(selected_suggestion_ui_1.SET_SUGGESTION_ID, dataTracked.id));
100
+ }
101
+ else {
102
+ if (isSelectedSuggestion) {
103
+ this.view.dispatch(this.view.state.tr.setMeta(selected_suggestion_ui_1.CLEAR_SUGGESTION_ID, true));
104
+ }
105
+ else {
106
+ this.showContextMenu(elementId);
107
+ }
108
+ }
109
+ };
63
110
  this.updateContents = () => __awaiter(this, void 0, void 0, function* () {
64
111
  const bib = (0, bibliography_1.getBibliographyPluginState)(this.view.state);
65
112
  const commentsDecorationSet = comment_annotation_1.commentAnnotation.getState(this.view.state);
@@ -94,28 +141,6 @@ class BibliographyElementBlockView extends block_view_1.default {
94
141
  const id = meta.entry_ids[i];
95
142
  const fragment = bibliography[i];
96
143
  const element = (0, dompurify_1.sanitize)(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${fragment}</div></div>`).firstElementChild;
97
- const doubleButton = document.createElement('div');
98
- const editButton = document.createElement('button');
99
- const commentButton = document.createElement('button');
100
- doubleButton.className = 'bibliography-double-button';
101
- editButton.className = 'bibliography-edit-button';
102
- commentButton.className = 'bibliography-comment-button';
103
- commentButton.addEventListener('click', (e) => {
104
- e.preventDefault();
105
- this.props.setComment((0, transform_1.buildComment)(element.id));
106
- });
107
- editButton.addEventListener('click', (e) => {
108
- e.preventDefault();
109
- this.showPopper(element.id);
110
- });
111
- editButton.innerHTML = assets_1.editIcon;
112
- commentButton.innerHTML = assets_1.commentIcon;
113
- doubleButton.append(editButton, commentButton);
114
- if (can.seeReferencesButtons &&
115
- !element.querySelector('.bibliography-double-button')) {
116
- element.appendChild(doubleButton);
117
- }
118
- editButton.disabled = !can.editCitationsAndRefs;
119
144
  const commentElement = commentElementMap.get(element.id);
120
145
  if (commentElement) {
121
146
  element.appendChild(commentElement);
@@ -123,16 +148,14 @@ class BibliographyElementBlockView extends block_view_1.default {
123
148
  const dataTracked = dataTrackedMap.get(element.id);
124
149
  if (dataTracked) {
125
150
  element.classList.add('attrs-track-mark', ...(0, track_changes_utils_1.getChangeClasses)([dataTracked]));
126
- if (dataTracked.status === track_changes_plugin_1.CHANGE_STATUS.pending &&
127
- dataTracked.operation === track_changes_plugin_1.CHANGE_OPERATION.set_node_attributes) {
128
- element.appendChild((0, track_changes_utils_1.getAttrsTrackingButton)(dataTracked.id));
129
- }
130
- this.addClickListenerToBibItem(element, dataTracked);
131
151
  }
132
152
  if (selectedBibItemSuggestion &&
133
153
  selectedBibItemSuggestion === element.id) {
134
154
  element.classList.add('selected-suggestion');
135
155
  }
156
+ if (can.seeReferencesButtons) {
157
+ element.addEventListener('click', () => this.onClickHandler(element.id, dataTracked));
158
+ }
136
159
  wrapper.append(element);
137
160
  }
138
161
  const oldContent = this.container.querySelector('.contents');
@@ -142,6 +165,9 @@ class BibliographyElementBlockView extends block_view_1.default {
142
165
  else {
143
166
  this.container.appendChild(wrapper);
144
167
  }
168
+ if (this.clickedElementId) {
169
+ this.showContextMenu(this.clickedElementId);
170
+ }
145
171
  });
146
172
  this.createElement = () => {
147
173
  this.container = document.createElement('div');
@@ -157,13 +183,6 @@ class BibliographyElementBlockView extends block_view_1.default {
157
183
  this.handleDelete = (item) => {
158
184
  (0, view_1.deleteNode)(this.view, item._id);
159
185
  };
160
- this.addClickListenerToBibItem = (element, dataTracked) => {
161
- if (dataTracked.status !== track_changes_plugin_1.CHANGE_STATUS.rejected) {
162
- element.addEventListener('click', () => {
163
- this.view.dispatch(this.view.state.tr.setMeta(selected_suggestion_ui_1.SET_SUGGESTION_ID, dataTracked.id));
164
- });
165
- }
166
- };
167
186
  }
168
187
  }
169
188
  exports.BibliographyElementBlockView = BibliographyElementBlockView;
@@ -14,15 +14,9 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
- var __importDefault = (this && this.__importDefault) || function (mod) {
18
- return (mod && mod.__esModule) ? mod : { "default": mod };
19
- };
20
17
  Object.defineProperty(exports, "__esModule", { value: true });
21
18
  exports.CitationView = void 0;
22
19
  const prosemirror_model_1 = require("prosemirror-model");
23
- const react_1 = require("react");
24
- const react_dom_1 = __importDefault(require("react-dom"));
25
- const TrackChangesReview_1 = require("../components/track-changes/TrackChangesReview");
26
20
  const dompurify_1 = require("../lib/dompurify");
27
21
  const track_changes_utils_1 = require("../lib/track-changes-utils");
28
22
  const bibliography_1 = require("../plugins/bibliography");
@@ -61,24 +55,8 @@ class CitationView extends base_node_view_1.BaseNodeView {
61
55
  this.dom.className = 'citation-wrapper';
62
56
  this.dom.innerHTML = '';
63
57
  this.dom.appendChild(element);
64
- if ((0, track_changes_utils_1.isPendingSetAttrs)(this.node) &&
65
- !(0, track_changes_utils_1.isDeleted)(this.node) &&
66
- citation.embeddedCitationItems.length) {
67
- this.dom.appendChild(this.renderTrackChangesReview());
68
- }
69
58
  this.setDomAttrs(this.node, this.dom, ['rids', 'contents', 'selectedText']);
70
59
  };
71
- this.renderTrackChangesReview = () => {
72
- const { popper } = this.props;
73
- const el = document.createElement('span');
74
- el.classList.add('track-changes-review');
75
- react_dom_1.default.render((0, react_1.createElement)(TrackChangesReview_1.TrackChangesReview, {
76
- node: this.node,
77
- popper,
78
- target: el,
79
- }), el);
80
- return el;
81
- };
82
60
  this.getCitation = () => {
83
61
  const citation = (0, bibliography_utils_1.getCitation)(this.node);
84
62
  if (!citation) {
@@ -29,6 +29,7 @@ const citation_sources_1 = require("../citation-sources");
29
29
  const track_changes_utils_1 = require("../lib/track-changes-utils");
30
30
  const view_1 = require("../lib/view");
31
31
  const bibliography_1 = require("../plugins/bibliography");
32
+ const selected_suggestion_ui_1 = require("../plugins/selected-suggestion-ui");
32
33
  const citation_1 = require("./citation");
33
34
  const CitationEditorWrapper_1 = require("./CitationEditorWrapper");
34
35
  const creators_1 = require("./creators");
@@ -42,14 +43,28 @@ class CitationEditableView extends citation_1.CitationView {
42
43
  super(...arguments);
43
44
  this.decoder = new transform_1.Decoder(new Map());
44
45
  this.selectNode = () => {
45
- if (!(0, track_changes_utils_1.isDeleted)(this.node)) {
46
- this.showPopper();
47
- this.dom.classList.add('ProseMirror-selectednode');
46
+ var _a;
47
+ const dataTracked = this.node.attrs.dataTracked;
48
+ const isSelectedSuggestion = !!((_a = selected_suggestion_ui_1.selectedSuggestionKey
49
+ .getState(this.view.state)) === null || _a === void 0 ? void 0 : _a.find(this.getPos(), this.getPos() + this.node.nodeSize).length);
50
+ this.dom.classList.add('ProseMirror-selectednode');
51
+ if (dataTracked && !isSelectedSuggestion) {
52
+ this.view.dispatch(this.view.state.tr.setMeta(selected_suggestion_ui_1.SET_SUGGESTION_ID, dataTracked[0].id));
53
+ }
54
+ else {
55
+ if (!(0, track_changes_utils_1.isDeleted)(this.node)) {
56
+ const citation = this.getCitation();
57
+ const rids = citation.embeddedCitationItems.map((i) => i.bibliographyItem);
58
+ if (!rids.length) {
59
+ this.showPopper();
60
+ }
61
+ else {
62
+ this.showContextMenu();
63
+ }
64
+ }
48
65
  }
49
66
  };
50
67
  this.deselectNode = () => {
51
- var _a;
52
- (_a = this.editor) === null || _a === void 0 ? void 0 : _a.remove();
53
68
  this.dom.classList.remove('ProseMirror-selectednode');
54
69
  this.props.popper.destroy();
55
70
  };
@@ -58,7 +73,18 @@ class CitationEditableView extends citation_1.CitationView {
58
73
  (_a = this.editor) === null || _a === void 0 ? void 0 : _a.remove();
59
74
  this.props.popper.destroy();
60
75
  };
76
+ this.showContextMenu = () => {
77
+ const componentProps = {
78
+ actions: [
79
+ { label: 'Edit', action: this.handleEdit, icon: 'EditIcon' },
80
+ { label: 'Comment', action: this.handleComment, icon: 'AddComment' },
81
+ ],
82
+ };
83
+ this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu');
84
+ this.props.popper.show(this.dom, this.contextMenu, 'right-start', false);
85
+ };
61
86
  this.showPopper = () => {
87
+ this.props.popper.destroy();
62
88
  const can = this.props.getCapabilities();
63
89
  const citation = this.getCitation();
64
90
  const rids = citation.embeddedCitationItems.map((i) => i.bibliographyItem);
@@ -91,6 +117,9 @@ class CitationEditableView extends citation_1.CitationView {
91
117
  }
92
118
  this.props.popper.show(this.dom, this.editor, 'right');
93
119
  };
120
+ this.handleEdit = () => {
121
+ this.showPopper();
122
+ };
94
123
  this.handleCancel = () => {
95
124
  const selection = prosemirror_state_1.TextSelection.create(this.view.state.tr.doc, this.getPos() + 1);
96
125
  this.view.dispatch(this.view.state.tr.setSelection(selection));
package/dist/es/assets.js CHANGED
@@ -115,3 +115,49 @@ export const alertIcon = `
115
115
  />
116
116
  </svg>
117
117
  `;
118
+ export const deleteIcon = `
119
+ <svg
120
+ width="13"
121
+ height="15"
122
+ viewBox="0 0 13 15"
123
+ fill="none"
124
+ xmlns="http://www.w3.org/2000/svg"
125
+ >
126
+ <path
127
+ fill-rule="evenodd"
128
+ clip-rule="evenodd"
129
+ d="M2.00001 3C2 3.00135 2 3.00269 2 3.00404V13.004C2 13.5563 2.44772 14.004 3 14.004H10C10.5523 14.004 11 13.5563 11 13.004V3.00404C11 3.00269 11 3.00135 11 3C11.5978 3.34581 12 3.99215 12 4.73244V13.004C12 14.1086 11.1046 15.004 10 15.004H3C1.89543 15.004 1 14.1086 1 13.004V4.73244C1 3.99215 1.4022 3.34581 2.00001 3Z"
130
+ fill="#C9C9C9"
131
+ />
132
+ <path
133
+ fill-rule="evenodd"
134
+ clip-rule="evenodd"
135
+ d="M4.5 0C3.67157 0 3 0.671573 3 1.5V3.5C3 4.32843 3.67157 5 4.5 5H8.5C9.32843 5 10 4.32843 10 3.5V1.5C10 0.671573 9.32843 0 8.5 0H4.5ZM9 1.5C9 1.22386 8.77614 1 8.5 1H4.5C4.22386 1 4 1.22386 4 1.5C4 1.77614 4.22386 2 4.5 2H8.5C8.77614 2 9 1.77614 9 1.5Z"
136
+ fill="#C9C9C9"
137
+ />
138
+ <rect
139
+ y="2"
140
+ width="13"
141
+ height="3"
142
+ rx="1.5"
143
+ fill="#C9C9C9"
144
+ />
145
+ <path
146
+ fill-rule="evenodd"
147
+ clip-rule="evenodd"
148
+ d="M8 7.5C8 7.22386 8.22386 7 8.5 7C8.77614 7 9 7.22386 9 7.5V11.5C9 11.7761 8.77614 12 8.5 12C8.22386 12 8 11.7761 8 11.5V7.5Z"
149
+ fill="#C9C9C9"
150
+ />
151
+ <path
152
+ fill-rule="evenodd"
153
+ clip-rule="evenodd"
154
+ d="M4 7.5C4 7.22386 4.22386 7 4.5 7C4.77614 7 5 7.22386 5 7.5V11.5C5 11.7761 4.77614 12 4.5 12C4.22386 12 4 11.7761 4 11.5V7.5Z"
155
+ fill="#C9C9C9"
156
+ />
157
+ <path
158
+ fill-rule="evenodd"
159
+ clip-rule="evenodd"
160
+ d="M11.5 3C11.7761 3 12 3.22386 12 3.5C12 3.77614 11.7761 4 11.5 4L1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3L11.5 3Z"
161
+ fill="white"
162
+ />
163
+ </svg>`;
@@ -0,0 +1,18 @@
1
+ import { Category, Dialog } from '@manuscripts/style-guide';
2
+ import React, { useState } from 'react';
3
+ export const DeleteFootnoteDialog = ({ footnoteType, footnoteMessage, handleDelete, }) => {
4
+ const [isOpen, setOpen] = useState(true);
5
+ return (React.createElement(Dialog, { isOpen: isOpen, actions: {
6
+ primary: {
7
+ action: () => setOpen(false),
8
+ title: 'Cancel',
9
+ },
10
+ secondary: {
11
+ action: () => {
12
+ setOpen(false);
13
+ handleDelete();
14
+ },
15
+ title: 'Delete',
16
+ },
17
+ }, category: Category.confirmation, header: `Delete ${footnoteType}`, message: `${footnoteMessage}` }));
18
+ };
@@ -63,7 +63,7 @@ export default (props) => {
63
63
  tableEditing(),
64
64
  highlights(props),
65
65
  selected_suggestion_ui(props),
66
- footnotes(),
66
+ footnotes(props),
67
67
  ];
68
68
  if (props.collabProvider) {
69
69
  allPlugins.push(collab({ version: props.collabProvider.currentVersion }));
@@ -15,11 +15,14 @@
15
15
  */
16
16
  import { isFootnoteNode, isInlineFootnoteNode, schema, } from '@manuscripts/transform';
17
17
  import { isEqual } from 'lodash';
18
- import { NodeSelection, Plugin, PluginKey } from 'prosemirror-state';
18
+ import { NodeSelection, Plugin, PluginKey, TextSelection, } from 'prosemirror-state';
19
19
  import { hasParentNodeOfType } from 'prosemirror-utils';
20
20
  import { Decoration, DecorationSet } from 'prosemirror-view';
21
- import { alertIcon } from '../../assets';
21
+ import { alertIcon, deleteIcon } from '../../assets';
22
+ import { DeleteFootnoteDialog, } from '../../components/views/DeleteFootnoteDialog';
23
+ import { isDeleted } from '../../lib/track-changes-utils';
22
24
  import { findParentNodeWithIdValue } from '../../lib/utils';
25
+ import ReactSubView from '../../views/ReactSubView';
23
26
  import { placeholderWidget } from '../placeholder';
24
27
  import { findTableInlineFootnoteIds } from './footnotes-utils';
25
28
  export const footnotesKey = new PluginKey('footnotes');
@@ -63,7 +66,60 @@ export const uncitedFootnoteWidget = () => () => {
63
66
  element.innerHTML = alertIcon;
64
67
  return element;
65
68
  };
66
- export default () => {
69
+ const getInlineFootnote = (view, id) => {
70
+ let inlineFootnote = null;
71
+ let footnotePosition = null;
72
+ view.state.doc.descendants((node, pos) => {
73
+ var _a;
74
+ const footnote = node;
75
+ if ((_a = footnote.attrs.rids) === null || _a === void 0 ? void 0 : _a.includes(id)) {
76
+ inlineFootnote = footnote;
77
+ footnotePosition = pos;
78
+ return false;
79
+ }
80
+ });
81
+ return { node: inlineFootnote, pos: footnotePosition };
82
+ };
83
+ const deleteFootnoteWidget = (node, pos, props, footnoteType, footnoteMessage, id) => (view) => {
84
+ const deleteBtn = document.createElement('span');
85
+ deleteBtn.className = 'delete-icon';
86
+ deleteBtn.innerHTML = deleteIcon;
87
+ deleteBtn.addEventListener('click', () => {
88
+ const handleDelete = () => {
89
+ const tr = view.state.tr;
90
+ if (node.type === schema.nodes.table_element_footer) {
91
+ node.content.forEach((item) => {
92
+ if (item.type === schema.nodes.paragraph) {
93
+ tr.delete(pos, pos + item.nodeSize + 1);
94
+ }
95
+ });
96
+ if (!node.childCount) {
97
+ tr.setSelection(TextSelection.near(view.state.doc.resolve(0))).delete(pos, pos + node.nodeSize + 1);
98
+ }
99
+ }
100
+ if (node.type === schema.nodes.footnote) {
101
+ const inlineFootnotes = getInlineFootnote(view, id);
102
+ tr.setSelection(TextSelection.near(view.state.doc.resolve(0))).delete(pos, pos + node.nodeSize + 1);
103
+ if (inlineFootnotes.node) {
104
+ const pos = inlineFootnotes.pos;
105
+ const nodeSize = inlineFootnotes.node.nodeSize;
106
+ if (pos && nodeSize) {
107
+ tr.delete(pos, pos + nodeSize);
108
+ }
109
+ }
110
+ }
111
+ view.dispatch(tr);
112
+ };
113
+ const componentProps = {
114
+ footnoteType: footnoteType,
115
+ footnoteMessage: footnoteMessage,
116
+ handleDelete: handleDelete,
117
+ };
118
+ ReactSubView(Object.assign(Object.assign({}, props), { dispatch: view.dispatch }), DeleteFootnoteDialog, componentProps, node, () => pos, view);
119
+ });
120
+ return deleteBtn;
121
+ };
122
+ export default (props) => {
67
123
  return new Plugin({
68
124
  key: footnotesKey,
69
125
  state: {
@@ -96,6 +152,7 @@ export default () => {
96
152
  decorations: (state) => {
97
153
  const decorations = [];
98
154
  const isInTableElementFooter = hasParentNodeOfType(schema.nodes.table_element_footer)(state.selection);
155
+ const isInTableElement = hasParentNodeOfType(schema.nodes.table_element)(state.selection);
99
156
  if (isInTableElementFooter) {
100
157
  const parent = findParentNodeWithIdValue(state.selection);
101
158
  if (parent) {
@@ -126,6 +183,40 @@ export default () => {
126
183
  decorations.push(Decoration.widget(pos + node.nodeSize - 1, uncitedFootnoteWidget()));
127
184
  }
128
185
  }
186
+ if (isInTableElement) {
187
+ const isGeneralFootnote = node.type === schema.nodes.paragraph;
188
+ const isTableFootnote = node.type === schema.nodes.footnote;
189
+ const footnote = (() => {
190
+ switch (node.type) {
191
+ case schema.nodes.footnote:
192
+ return {
193
+ type: 'table footnote',
194
+ message: 'This action will entirely remove the table footnote from the list because it will no longer be used.',
195
+ };
196
+ default:
197
+ return {
198
+ type: 'table general note',
199
+ message: 'This action will entirely remove the table general note.',
200
+ };
201
+ }
202
+ })();
203
+ if (isTableFootnote) {
204
+ decorations.push(Decoration.widget(pos + 2, deleteFootnoteWidget(node, pos, props, footnote.type, footnote.message, node.attrs.id), {
205
+ key: node.attrs.id,
206
+ }));
207
+ }
208
+ else if (isGeneralFootnote &&
209
+ (parent === null || parent === void 0 ? void 0 : parent.type) === schema.nodes.table_element_footer) {
210
+ decorations.push(Decoration.widget(pos + 2, deleteFootnoteWidget(parent, pos, props, footnote.type, footnote.message, parent.attrs.id), {
211
+ key: parent.attrs.id,
212
+ }));
213
+ }
214
+ if (isDeleted(node)) {
215
+ decorations.push(Decoration.node(pos, pos + node.nodeSize, {
216
+ class: 'deleted-footnote',
217
+ }));
218
+ }
219
+ }
129
220
  if (node.type === schema.nodes.footnotes_element) {
130
221
  if ((parent === null || parent === void 0 ? void 0 : parent.type) === schema.nodes.table_element_footer) {
131
222
  decorations.push(Decoration.node(pos, pos + node.nodeSize, {
@@ -78,7 +78,7 @@ const getTrackChangesData = (node) => {
78
78
  return (_a = trackChangesMark === null || trackChangesMark === void 0 ? void 0 : trackChangesMark.attrs) === null || _a === void 0 ? void 0 : _a.dataTracked;
79
79
  };
80
80
  export const SET_SUGGESTION_ID = 'SET_SELECTED_SUGGESTION_ID';
81
- const CLEAR_SUGGESTION_ID = 'CLEAR_SUGGESTION_ID';
81
+ export const CLEAR_SUGGESTION_ID = 'CLEAR_SUGGESTION_ID';
82
82
  export const selectedSuggestionKey = new PluginKey('selected_suggestion');
83
83
  export default (props) => new Plugin({
84
84
  key: selectedSuggestionKey,
@@ -22,15 +22,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
22
22
  step((generator = generator.apply(thisArg, _arguments || [])).next());
23
23
  });
24
24
  };
25
- import { CHANGE_OPERATION, CHANGE_STATUS, } from '@manuscripts/track-changes-plugin';
25
+ import { ContextMenu } from '@manuscripts/style-guide';
26
+ import { CHANGE_STATUS } from '@manuscripts/track-changes-plugin';
26
27
  import { buildComment, Decoder, } from '@manuscripts/transform';
27
- import { commentIcon, editIcon } from '../assets';
28
28
  import { sanitize } from '../lib/dompurify';
29
- import { getAttrsTrackingButton, getChangeClasses, } from '../lib/track-changes-utils';
29
+ import { getChangeClasses } from '../lib/track-changes-utils';
30
30
  import { deleteNode, updateNode } from '../lib/view';
31
31
  import { getBibliographyPluginState } from '../plugins/bibliography';
32
32
  import { commentAnnotation } from '../plugins/comment_annotation';
33
- import { selectedSuggestionKey, SET_SUGGESTION_ID, } from '../plugins/selected-suggestion-ui';
33
+ import { CLEAR_SUGGESTION_ID, selectedSuggestionKey, SET_SUGGESTION_ID, } from '../plugins/selected-suggestion-ui';
34
34
  import BlockView from './block_view';
35
35
  import { createNodeView } from './creators';
36
36
  import ReactSubView from './ReactSubView';
@@ -39,8 +39,9 @@ export class BibliographyElementBlockView extends BlockView {
39
39
  constructor() {
40
40
  super(...arguments);
41
41
  this.decoder = new Decoder(new Map());
42
- this.gutterButtons = () => [];
42
+ this.clickedElementId = null;
43
43
  this.showPopper = (id) => {
44
+ this.props.popper.destroy();
44
45
  const bib = getBibliographyPluginState(this.view.state);
45
46
  const componentProps = {
46
47
  items: Array.from(bib.bibliographyItems.values()),
@@ -54,6 +55,52 @@ export class BibliographyElementBlockView extends BlockView {
54
55
  };
55
56
  this.stopEvent = () => true;
56
57
  this.ignoreMutation = () => true;
58
+ this.handleEdit = (citationId) => {
59
+ this.showPopper(citationId);
60
+ };
61
+ this.handleComment = (citationId) => {
62
+ this.props.setComment(buildComment(citationId));
63
+ };
64
+ this.showContextMenu = (elementId) => {
65
+ this.props.popper.destroy();
66
+ this.clickedElementId = null;
67
+ const can = this.props.getCapabilities();
68
+ const element = document.getElementById(elementId);
69
+ const componentProps = {
70
+ actions: [],
71
+ };
72
+ if (can.editCitationsAndRefs) {
73
+ componentProps.actions.push({
74
+ label: 'Edit',
75
+ action: () => this.handleEdit(elementId),
76
+ icon: 'EditIcon',
77
+ });
78
+ }
79
+ componentProps.actions.push({
80
+ label: 'Comment',
81
+ action: () => this.handleComment(elementId),
82
+ icon: 'AddComment',
83
+ });
84
+ this.contextMenu = ReactSubView(this.props, ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu');
85
+ this.props.popper.show(element, this.contextMenu, 'right-start');
86
+ };
87
+ this.onClickHandler = (elementId, dataTracked) => {
88
+ var _a;
89
+ this.clickedElementId = elementId;
90
+ const isSelectedSuggestion = !!((_a = selectedSuggestionKey
91
+ .getState(this.view.state)) === null || _a === void 0 ? void 0 : _a.find(this.getPos(), this.getPos() + this.node.nodeSize).length);
92
+ if (dataTracked && dataTracked.status !== CHANGE_STATUS.rejected) {
93
+ this.view.dispatch(this.view.state.tr.setMeta(SET_SUGGESTION_ID, dataTracked.id));
94
+ }
95
+ else {
96
+ if (isSelectedSuggestion) {
97
+ this.view.dispatch(this.view.state.tr.setMeta(CLEAR_SUGGESTION_ID, true));
98
+ }
99
+ else {
100
+ this.showContextMenu(elementId);
101
+ }
102
+ }
103
+ };
57
104
  this.updateContents = () => __awaiter(this, void 0, void 0, function* () {
58
105
  const bib = getBibliographyPluginState(this.view.state);
59
106
  const commentsDecorationSet = commentAnnotation.getState(this.view.state);
@@ -88,28 +135,6 @@ export class BibliographyElementBlockView extends BlockView {
88
135
  const id = meta.entry_ids[i];
89
136
  const fragment = bibliography[i];
90
137
  const element = sanitize(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${fragment}</div></div>`).firstElementChild;
91
- const doubleButton = document.createElement('div');
92
- const editButton = document.createElement('button');
93
- const commentButton = document.createElement('button');
94
- doubleButton.className = 'bibliography-double-button';
95
- editButton.className = 'bibliography-edit-button';
96
- commentButton.className = 'bibliography-comment-button';
97
- commentButton.addEventListener('click', (e) => {
98
- e.preventDefault();
99
- this.props.setComment(buildComment(element.id));
100
- });
101
- editButton.addEventListener('click', (e) => {
102
- e.preventDefault();
103
- this.showPopper(element.id);
104
- });
105
- editButton.innerHTML = editIcon;
106
- commentButton.innerHTML = commentIcon;
107
- doubleButton.append(editButton, commentButton);
108
- if (can.seeReferencesButtons &&
109
- !element.querySelector('.bibliography-double-button')) {
110
- element.appendChild(doubleButton);
111
- }
112
- editButton.disabled = !can.editCitationsAndRefs;
113
138
  const commentElement = commentElementMap.get(element.id);
114
139
  if (commentElement) {
115
140
  element.appendChild(commentElement);
@@ -117,16 +142,14 @@ export class BibliographyElementBlockView extends BlockView {
117
142
  const dataTracked = dataTrackedMap.get(element.id);
118
143
  if (dataTracked) {
119
144
  element.classList.add('attrs-track-mark', ...getChangeClasses([dataTracked]));
120
- if (dataTracked.status === CHANGE_STATUS.pending &&
121
- dataTracked.operation === CHANGE_OPERATION.set_node_attributes) {
122
- element.appendChild(getAttrsTrackingButton(dataTracked.id));
123
- }
124
- this.addClickListenerToBibItem(element, dataTracked);
125
145
  }
126
146
  if (selectedBibItemSuggestion &&
127
147
  selectedBibItemSuggestion === element.id) {
128
148
  element.classList.add('selected-suggestion');
129
149
  }
150
+ if (can.seeReferencesButtons) {
151
+ element.addEventListener('click', () => this.onClickHandler(element.id, dataTracked));
152
+ }
130
153
  wrapper.append(element);
131
154
  }
132
155
  const oldContent = this.container.querySelector('.contents');
@@ -136,6 +159,9 @@ export class BibliographyElementBlockView extends BlockView {
136
159
  else {
137
160
  this.container.appendChild(wrapper);
138
161
  }
162
+ if (this.clickedElementId) {
163
+ this.showContextMenu(this.clickedElementId);
164
+ }
139
165
  });
140
166
  this.createElement = () => {
141
167
  this.container = document.createElement('div');
@@ -151,13 +177,6 @@ export class BibliographyElementBlockView extends BlockView {
151
177
  this.handleDelete = (item) => {
152
178
  deleteNode(this.view, item._id);
153
179
  };
154
- this.addClickListenerToBibItem = (element, dataTracked) => {
155
- if (dataTracked.status !== CHANGE_STATUS.rejected) {
156
- element.addEventListener('click', () => {
157
- this.view.dispatch(this.view.state.tr.setMeta(SET_SUGGESTION_ID, dataTracked.id));
158
- });
159
- }
160
- };
161
180
  }
162
181
  }
163
182
  export default createNodeView(BibliographyElementBlockView);
@@ -14,11 +14,8 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { DOMSerializer } from 'prosemirror-model';
17
- import { createElement } from 'react';
18
- import ReactDOM from 'react-dom';
19
- import { TrackChangesReview } from '../components/track-changes/TrackChangesReview';
20
17
  import { sanitize } from '../lib/dompurify';
21
- import { getChangeClasses, isDeleted, isPendingSetAttrs, } from '../lib/track-changes-utils';
18
+ import { getChangeClasses } from '../lib/track-changes-utils';
22
19
  import { getBibliographyPluginState } from '../plugins/bibliography';
23
20
  import { getCitation } from '../plugins/bibliography/bibliography-utils';
24
21
  import { BaseNodeView } from './base_node_view';
@@ -55,24 +52,8 @@ export class CitationView extends BaseNodeView {
55
52
  this.dom.className = 'citation-wrapper';
56
53
  this.dom.innerHTML = '';
57
54
  this.dom.appendChild(element);
58
- if (isPendingSetAttrs(this.node) &&
59
- !isDeleted(this.node) &&
60
- citation.embeddedCitationItems.length) {
61
- this.dom.appendChild(this.renderTrackChangesReview());
62
- }
63
55
  this.setDomAttrs(this.node, this.dom, ['rids', 'contents', 'selectedText']);
64
56
  };
65
- this.renderTrackChangesReview = () => {
66
- const { popper } = this.props;
67
- const el = document.createElement('span');
68
- el.classList.add('track-changes-review');
69
- ReactDOM.render(createElement(TrackChangesReview, {
70
- node: this.node,
71
- popper,
72
- target: el,
73
- }), el);
74
- return el;
75
- };
76
57
  this.getCitation = () => {
77
58
  const citation = getCitation(this.node);
78
59
  if (!citation) {
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { ObjectTypes, } from '@manuscripts/json-schema';
17
17
  import { findMatchingBibliographyItem } from '@manuscripts/library';
18
- import { CitationViewer, } from '@manuscripts/style-guide';
18
+ import { CitationViewer, ContextMenu, } from '@manuscripts/style-guide';
19
19
  import { buildComment, Decoder, schema, } from '@manuscripts/transform';
20
20
  import { TextSelection } from 'prosemirror-state';
21
21
  import { findChildren, findChildrenByType } from 'prosemirror-utils';
@@ -23,6 +23,7 @@ import { crossref } from '../citation-sources';
23
23
  import { isDeleted } from '../lib/track-changes-utils';
24
24
  import { deleteNode, updateNodeAttrs } from '../lib/view';
25
25
  import { getBibliographyPluginState } from '../plugins/bibliography';
26
+ import { selectedSuggestionKey, SET_SUGGESTION_ID, } from '../plugins/selected-suggestion-ui';
26
27
  import { CitationView } from './citation';
27
28
  import { CitationEditorWrapper } from './CitationEditorWrapper';
28
29
  import { createEditableNodeView } from './creators';
@@ -36,14 +37,28 @@ export class CitationEditableView extends CitationView {
36
37
  super(...arguments);
37
38
  this.decoder = new Decoder(new Map());
38
39
  this.selectNode = () => {
39
- if (!isDeleted(this.node)) {
40
- this.showPopper();
41
- this.dom.classList.add('ProseMirror-selectednode');
40
+ var _a;
41
+ const dataTracked = this.node.attrs.dataTracked;
42
+ const isSelectedSuggestion = !!((_a = selectedSuggestionKey
43
+ .getState(this.view.state)) === null || _a === void 0 ? void 0 : _a.find(this.getPos(), this.getPos() + this.node.nodeSize).length);
44
+ this.dom.classList.add('ProseMirror-selectednode');
45
+ if (dataTracked && !isSelectedSuggestion) {
46
+ this.view.dispatch(this.view.state.tr.setMeta(SET_SUGGESTION_ID, dataTracked[0].id));
47
+ }
48
+ else {
49
+ if (!isDeleted(this.node)) {
50
+ const citation = this.getCitation();
51
+ const rids = citation.embeddedCitationItems.map((i) => i.bibliographyItem);
52
+ if (!rids.length) {
53
+ this.showPopper();
54
+ }
55
+ else {
56
+ this.showContextMenu();
57
+ }
58
+ }
42
59
  }
43
60
  };
44
61
  this.deselectNode = () => {
45
- var _a;
46
- (_a = this.editor) === null || _a === void 0 ? void 0 : _a.remove();
47
62
  this.dom.classList.remove('ProseMirror-selectednode');
48
63
  this.props.popper.destroy();
49
64
  };
@@ -52,7 +67,18 @@ export class CitationEditableView extends CitationView {
52
67
  (_a = this.editor) === null || _a === void 0 ? void 0 : _a.remove();
53
68
  this.props.popper.destroy();
54
69
  };
70
+ this.showContextMenu = () => {
71
+ const componentProps = {
72
+ actions: [
73
+ { label: 'Edit', action: this.handleEdit, icon: 'EditIcon' },
74
+ { label: 'Comment', action: this.handleComment, icon: 'AddComment' },
75
+ ],
76
+ };
77
+ this.contextMenu = ReactSubView(this.props, ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu');
78
+ this.props.popper.show(this.dom, this.contextMenu, 'right-start', false);
79
+ };
55
80
  this.showPopper = () => {
81
+ this.props.popper.destroy();
56
82
  const can = this.props.getCapabilities();
57
83
  const citation = this.getCitation();
58
84
  const rids = citation.embeddedCitationItems.map((i) => i.bibliographyItem);
@@ -85,6 +111,9 @@ export class CitationEditableView extends CitationView {
85
111
  }
86
112
  this.props.popper.show(this.dom, this.editor, 'right');
87
113
  };
114
+ this.handleEdit = () => {
115
+ this.showPopper();
116
+ };
88
117
  this.handleCancel = () => {
89
118
  const selection = TextSelection.create(this.view.state.tr.doc, this.getPos() + 1);
90
119
  this.view.dispatch(this.view.state.tr.setSelection(selection));
@@ -17,3 +17,4 @@ export declare const editIcon = "\n <svg\n width=\"14\"\n height=\"14\"\n
17
17
  export declare const commentIcon = "\n<svg\n width=\"20\"\n height=\"15\"\n viewBox=\"0 0 20 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M7.94841 4.18311C7.98238 3.9602 8 3.73191 8 3.49951C8 3.22073 7.97465 2.94787 7.92613 2.68311H13.5C14.8854 2.68311 16.25 3.6425 16.25 5.09977V9.02453L19.1086 12.9949C19.2731 13.2233 19.2958 13.5245 19.1675 13.775C19.0392 14.0255 18.7814 14.1831 18.5 14.1831H5.5C4.11463 14.1831 2.75 13.2237 2.75 11.7664V7.93729C2.9939 7.97821 3.24446 7.99951 3.5 7.99951C3.75553 7.99951 4.00609 7.97821 4.25 7.93729V11.7664C4.25 12.1508 4.67537 12.6831 5.5 12.6831H17.0358L14.8913 9.70467C14.7994 9.57703 14.75 9.42372 14.75 9.26644V5.09977C14.75 4.71538 14.3246 4.18311 13.5 4.18311H7.94841Z\"\n fill=\"#FFBD26\"\n />\n <path\n d=\"M11.5 6.99951H8.5\"\n stroke=\"#FFBD26\"\n stroke-width=\"1.5\"\n stroke-miterlimit=\"10\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M12 9.99951H7\"\n stroke=\"#FFBD26\"\n stroke-width=\"1.5\"\n stroke-miterlimit=\"10\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M3.5 1L3.5 6\"\n stroke=\"#FFBD26\"\n stroke-width=\"1.5\"\n stroke-miterlimit=\"10\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M6 3.5L1 3.5\"\n stroke=\"#FFBD26\"\n stroke-width=\"1.5\"\n stroke-miterlimit=\"10\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n";
18
18
  export declare const editAttrsTrackingIcon = "\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L14 4L9 9L6 10L7 7L12 2Z\"\n stroke=\"#353535\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M13 10V11.5C13 12.328 12.328 13 11.5 13H4.5C3.672 13 3 12.328 3 11.5V4.5C3 3.672 3.672 3 4.5 3H6\"\n stroke=\"#353535\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n";
19
19
  export declare const alertIcon = "\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M6 12C2.68629 12 1.18852e-06 9.31371 1.47821e-06 6C1.7679e-06 2.68629 2.68629 1.39444e-07 6 4.29138e-07C9.31371 7.18831e-07 12 2.68629 12 6C12 9.31371 9.31371 12 6 12ZM6.74998 2.99996L6.75 6.37462C6.75 6.78819 6.41522 7.12243 6.00166 7.12334C5.58681 7.12426 5.25001 6.78821 5.25001 6.37335L5.25 3.00082C5.25 2.58629 5.58629 2.25037 6.00082 2.25083C6.4147 2.25128 6.74998 2.58607 6.74998 2.99996ZM6.75 8.99263C6.75 9.46884 6.47288 9.75 5.99853 9.75C5.52419 9.75 5.25 9.47179 5.25 8.99558C5.25 8.51937 5.52421 8.25 5.99855 8.25C6.47289 8.25 6.75 8.51642 6.75 8.99263Z\"\n fill=\"#FE8F1F\"\n />\n </svg>\n";
20
+ export declare const deleteIcon = "\n <svg \n width=\"13\" \n height=\"15\" \n viewBox=\"0 0 13 15\" \n fill=\"none\" \n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path \n fill-rule=\"evenodd\" \n clip-rule=\"evenodd\" \n d=\"M2.00001 3C2 3.00135 2 3.00269 2 3.00404V13.004C2 13.5563 2.44772 14.004 3 14.004H10C10.5523 14.004 11 13.5563 11 13.004V3.00404C11 3.00269 11 3.00135 11 3C11.5978 3.34581 12 3.99215 12 4.73244V13.004C12 14.1086 11.1046 15.004 10 15.004H3C1.89543 15.004 1 14.1086 1 13.004V4.73244C1 3.99215 1.4022 3.34581 2.00001 3Z\" \n fill=\"#C9C9C9\"\n />\n <path \n fill-rule=\"evenodd\" \n clip-rule=\"evenodd\" \n d=\"M4.5 0C3.67157 0 3 0.671573 3 1.5V3.5C3 4.32843 3.67157 5 4.5 5H8.5C9.32843 5 10 4.32843 10 3.5V1.5C10 0.671573 9.32843 0 8.5 0H4.5ZM9 1.5C9 1.22386 8.77614 1 8.5 1H4.5C4.22386 1 4 1.22386 4 1.5C4 1.77614 4.22386 2 4.5 2H8.5C8.77614 2 9 1.77614 9 1.5Z\" \n fill=\"#C9C9C9\"\n />\n <rect \n y=\"2\" \n width=\"13\" \n height=\"3\" \n rx=\"1.5\" \n fill=\"#C9C9C9\"\n />\n <path \n fill-rule=\"evenodd\" \n clip-rule=\"evenodd\" \n d=\"M8 7.5C8 7.22386 8.22386 7 8.5 7C8.77614 7 9 7.22386 9 7.5V11.5C9 11.7761 8.77614 12 8.5 12C8.22386 12 8 11.7761 8 11.5V7.5Z\" \n fill=\"#C9C9C9\"\n />\n <path \n fill-rule=\"evenodd\" \n clip-rule=\"evenodd\" \n d=\"M4 7.5C4 7.22386 4.22386 7 4.5 7C4.77614 7 5 7.22386 5 7.5V11.5C5 11.7761 4.77614 12 4.5 12C4.22386 12 4 11.7761 4 11.5V7.5Z\" \n fill=\"#C9C9C9\"\n />\n <path \n fill-rule=\"evenodd\" \n clip-rule=\"evenodd\" \n d=\"M11.5 3C11.7761 3 12 3.22386 12 3.5C12 3.77614 11.7761 4 11.5 4L1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3L11.5 3Z\" \n fill=\"white\"\n />\n</svg>";
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface DeleteFootnoteDialogProps {
3
+ footnoteType: string;
4
+ footnoteMessage: string;
5
+ handleDelete: () => void;
6
+ }
7
+ export declare const DeleteFootnoteDialog: React.FC<DeleteFootnoteDialogProps>;
@@ -22,7 +22,7 @@ import { Plugin } from 'prosemirror-state';
22
22
  import { CollabProvider } from '../classes/collabProvider';
23
23
  import { PopperManager } from '../lib/popper';
24
24
  import { CSLProps } from './ManuscriptsEditor';
25
- interface PluginProps {
25
+ export interface PluginProps {
26
26
  getManuscript: () => Manuscript;
27
27
  setComment: (comment?: CommentAnnotation) => void;
28
28
  setSelectedComment: (id?: string) => void;
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { InlineFootnoteNode, ManuscriptNode } from '@manuscripts/transform';
17
17
  import { Plugin, PluginKey } from 'prosemirror-state';
18
+ import { PluginProps } from '../../configs/editor-plugins';
18
19
  interface PluginState {
19
20
  nodes: [InlineFootnoteNode, number][];
20
21
  labels: Map<string, string>;
@@ -22,5 +23,5 @@ interface PluginState {
22
23
  export declare const footnotesKey: PluginKey<PluginState>;
23
24
  export declare const buildPluginState: (doc: ManuscriptNode) => PluginState;
24
25
  export declare const uncitedFootnoteWidget: () => () => HTMLSpanElement;
25
- declare const _default: () => Plugin<PluginState>;
26
+ declare const _default: (props: PluginProps) => Plugin<PluginState>;
26
27
  export default _default;
@@ -19,6 +19,7 @@ interface SelectedSuggestionProps {
19
19
  setEditorSelectedSuggestion: (id?: string) => void;
20
20
  }
21
21
  export declare const SET_SUGGESTION_ID = "SET_SELECTED_SUGGESTION_ID";
22
+ export declare const CLEAR_SUGGESTION_ID = "CLEAR_SUGGESTION_ID";
22
23
  export declare const selectedSuggestionKey: PluginKey<DecorationSet>;
23
24
  declare const _default: (props: SelectedSuggestionProps) => Plugin<DecorationSet>;
24
25
  export default _default;
@@ -23,16 +23,20 @@ interface BibliographyElementViewProps extends BaseNodeProps {
23
23
  export declare class BibliographyElementBlockView<PropsType extends BibliographyElementViewProps & EditableBlockProps> extends BlockView<PropsType> {
24
24
  private container;
25
25
  private editor;
26
+ private contextMenu;
26
27
  private decoder;
27
- gutterButtons: () => HTMLElement[];
28
+ private clickedElementId;
28
29
  showPopper: (id: string) => void;
29
30
  stopEvent: () => boolean;
30
31
  ignoreMutation: () => boolean;
32
+ private handleEdit;
33
+ private handleComment;
34
+ showContextMenu: (elementId: string) => void;
35
+ private onClickHandler;
31
36
  updateContents: () => Promise<void>;
32
37
  createElement: () => void;
33
38
  private handleSave;
34
39
  private handleDelete;
35
- private addClickListenerToBibItem;
36
40
  }
37
41
  declare const _default: (props: BaseNodeProps, dispatch?: import("..").Dispatch | undefined) => import("../types").NodeViewCreator<BibliographyElementBlockView<any>>;
38
42
  export default _default;
@@ -19,7 +19,6 @@ export declare class CitationView<PropsType extends BaseNodeProps> extends BaseN
19
19
  ignoreMutation: () => boolean;
20
20
  initialise: () => this;
21
21
  updateContents: () => void;
22
- renderTrackChangesReview: () => HTMLSpanElement;
23
22
  getCitation: () => import("@manuscripts/json-schema/dist/types").Citation;
24
23
  }
25
24
  declare const _default: (props: BaseNodeProps, dispatch?: import("..").Dispatch | undefined) => import("../types").NodeViewCreator<CitationView<any>>;
@@ -18,10 +18,13 @@ import { EditableBlockProps } from './editable_block';
18
18
  export declare class CitationEditableView extends CitationView<EditableBlockProps> {
19
19
  private decoder;
20
20
  private editor;
21
+ private contextMenu;
21
22
  selectNode: () => void;
22
23
  deselectNode: () => void;
23
24
  destroy: () => void;
25
+ showContextMenu: () => void;
24
26
  showPopper: () => void;
27
+ private handleEdit;
25
28
  private handleCancel;
26
29
  private handleSave;
27
30
  private handleUncite;
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.25",
4
+ "version": "1.7.26-LEAN-3143-0",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -31,9 +31,9 @@
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.1",
34
+ "@manuscripts/style-guide": "1.8.2",
35
35
  "@manuscripts/track-changes-plugin": "1.7.8",
36
- "@manuscripts/transform": "^2.1.6",
36
+ "@manuscripts/transform": "2.1.9-LEAN-3321",
37
37
  "astrocite-eutils": "^0.16.4",
38
38
  "axios": "^1.6.7",
39
39
  "mathjax-full": "^3.2.2",
@@ -112,4 +112,4 @@
112
112
  "@types/react": "^17.0.2",
113
113
  "prosemirror-tables": "^1.3.5"
114
114
  }
115
- }
115
+ }
@@ -741,6 +741,7 @@ Next levels are shifted 'up' by 1
741
741
  .citation-wrapper {
742
742
  position: relative;
743
743
  }
744
+
744
745
  .track-changes-review {
745
746
  display: none;
746
747
  height: 36px;
package/styles/Editor.css CHANGED
@@ -671,6 +671,10 @@
671
671
  cursor: ns-resize;
672
672
  opacity: 0;
673
673
  transition: 0.2s all;
674
+ }
675
+
676
+ .ProseMirror .block-section_title .block-gutter,
677
+ .ProseMirror .block-paragraph .block-gutter {
674
678
  margin-top: 16px;
675
679
  }
676
680
 
@@ -954,8 +958,18 @@
954
958
  .ProseMirror .table-footnotes-element {
955
959
  counter-reset: table_footnote;
956
960
  }
957
-
958
- .ProseMirror .table-footnotes-element > div:not(:has(.unctied-table-footnote)) p::before {
961
+ .table-footer .delete-icon {
962
+ display: none;
963
+ position: absolute;
964
+ right: -20px;
965
+ top: -13px;
966
+ cursor: pointer;
967
+ z-index: 1;
968
+ }
969
+ .table-footer .delete-icon:hover svg path {
970
+ fill: #353535;
971
+ }
972
+ .ProseMirror .table-footer .table-footnotes-element > div:not(:has(.unctied-table-footnote)) p::before {
959
973
  counter-increment: table_footnote;
960
974
  content: counter(table_footnote);
961
975
  display: inline-block;
@@ -975,9 +989,17 @@
975
989
  background-color: #f2fbfc;
976
990
  padding: 4px;
977
991
  }
992
+
993
+ .ProseMirror .table-footer .footnote-selected .delete-icon ,.ProseMirror .table-footer .footnote-selected .deleted.rejected .delete-icon {
994
+ display: block;
995
+ }
978
996
  .table-footer > div > p {
979
997
  padding-bottom: 10px;
980
998
  }
999
+ .ProseMirror .table-footer .footnote-selected {
1000
+ position: relative;
1001
+ }
1002
+
981
1003
  .ProseMirror .table-footnotes-element .footnote-selected {
982
1004
  border: 1px solid #bce7f6;
983
1005
  }
@@ -1028,4 +1050,4 @@
1028
1050
  }
1029
1051
  .highlight {
1030
1052
  background-color: #ffeebf !important;
1031
- }
1053
+ }
package/styles/popper.css CHANGED
@@ -1,11 +1,10 @@
1
1
  .popper {
2
2
  color: #353535;
3
3
  font-family: 'PT Sans', sans-serif;
4
- min-width: 100px;
4
+ /* min-width: 100px; */
5
5
  position: absolute;
6
6
  width: auto;
7
7
  z-index: 5;
8
- /*opacity: 0.9;*/
9
8
  }
10
9
 
11
10
  .popper-arrow {
@@ -136,7 +135,8 @@
136
135
  .popper .cross-reference-editor,
137
136
  .popper .citation-references,
138
137
  .popper .track-changes-review-panel,
139
- .popper .table-footnote-editor {
138
+ .popper .table-footnote-editor,
139
+ .popper .context-menu {
140
140
  background: #fff;
141
141
  border: 1px solid #e2e2e2;
142
142
  border-radius: 8px;
@@ -144,6 +144,11 @@
144
144
  height: auto;
145
145
  }
146
146
 
147
+ .popper .context-menu {
148
+ width: auto;
149
+ top: -12px;
150
+ }
151
+
147
152
  .popper .conflict-dropdown {
148
153
  background: #fff;
149
154
  box-shadow: 0 4px 9px 0 rgba(84, 83, 83, 0.3);