@manuscripts/body-editor 3.17.0 → 3.17.1
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/lib/popper.js +4 -3
- package/dist/cjs/lib/position-menu.js +1 -1
- package/dist/cjs/lib/view.js +10 -1
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/footnote.js +43 -18
- package/dist/cjs/views/general_table_footnote.js +31 -21
- package/dist/es/lib/popper.js +4 -3
- package/dist/es/lib/position-menu.js +1 -1
- package/dist/es/lib/view.js +8 -0
- package/dist/es/versions.js +1 -1
- package/dist/es/views/footnote.js +43 -18
- package/dist/es/views/general_table_footnote.js +31 -21
- package/dist/types/lib/popper.d.ts +1 -1
- package/dist/types/lib/view.d.ts +3 -1
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/footnote.d.ts +5 -2
- package/dist/types/views/general_table_footnote.d.ts +2 -2
- package/package.json +2 -2
- package/src/lib/popper.ts +5 -3
- package/src/lib/position-menu.ts +1 -0
- package/src/lib/view.ts +17 -0
- package/src/versions.ts +1 -1
- package/src/views/footnote.ts +69 -33
- package/src/views/general_table_footnote.ts +43 -20
package/dist/cjs/lib/popper.js
CHANGED
|
@@ -22,7 +22,7 @@ class PopperManager {
|
|
|
22
22
|
constructor() {
|
|
23
23
|
this.isActive = () => !!this.activePopper;
|
|
24
24
|
}
|
|
25
|
-
show(target, contents, placement = 'bottom', showArrow = true, modifiers = [], autoFocus = true, onDestroy = undefined) {
|
|
25
|
+
show(target, contents, placement = 'bottom', showArrow = true, modifiers = [], autoFocus = true, autoCloseOnOutsideClick = true, onDestroy = undefined) {
|
|
26
26
|
this.destroy();
|
|
27
27
|
this.triggerElement = target;
|
|
28
28
|
this.destructionListener = onDestroy;
|
|
@@ -85,9 +85,10 @@ class PopperManager {
|
|
|
85
85
|
this.destroy();
|
|
86
86
|
}
|
|
87
87
|
};
|
|
88
|
-
if (contents.classList.contains('context-menu') ||
|
|
88
|
+
if ((contents.classList.contains('context-menu') ||
|
|
89
89
|
contents.classList.contains('language') ||
|
|
90
|
-
contents.classList.contains('section-category'))
|
|
90
|
+
contents.classList.contains('section-category')) &&
|
|
91
|
+
autoCloseOnOutsideClick) {
|
|
91
92
|
window.addEventListener('click', this.handleDocumentClick);
|
|
92
93
|
}
|
|
93
94
|
});
|
|
@@ -177,7 +177,7 @@ class HorizontalPositionMenu {
|
|
|
177
177
|
p.props.popper.replaceContent(content);
|
|
178
178
|
}
|
|
179
179
|
else {
|
|
180
|
-
p.props.popper.show(this.positionMenuWrapper, content, 'left', false, [], true, () => {
|
|
180
|
+
p.props.popper.show(this.positionMenuWrapper, content, 'left', false, [], true, true, () => {
|
|
181
181
|
this.menuOpen = false;
|
|
182
182
|
});
|
|
183
183
|
this.menuOpen = true;
|
package/dist/cjs/lib/view.js
CHANGED
|
@@ -48,7 +48,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
48
48
|
};
|
|
49
49
|
})();
|
|
50
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.saveBibliographyItem = exports.insertBibliographyItems = exports.deleteNode = exports.updateNodeAttrs = exports.findChildrenAttrsByType = exports.findChildrenByType = exports.findChildByType = exports.findChildByID = void 0;
|
|
51
|
+
exports.isSelectionInsideNode = exports.saveBibliographyItem = exports.insertBibliographyItems = exports.deleteNode = exports.updateNodeAttrs = exports.findChildrenAttrsByType = exports.findChildrenByType = exports.findChildByType = exports.findChildByID = void 0;
|
|
52
52
|
const transform_1 = require("@manuscripts/transform");
|
|
53
53
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
54
54
|
const utils = __importStar(require("prosemirror-utils"));
|
|
@@ -144,3 +144,12 @@ const saveBibliographyItem = (view, attrs) => {
|
|
|
144
144
|
(0, exports.insertBibliographyItems)(view, attrs);
|
|
145
145
|
};
|
|
146
146
|
exports.saveBibliographyItem = saveBibliographyItem;
|
|
147
|
+
const isSelectionInsideNode = (view, node, pos) => {
|
|
148
|
+
const { from, to, empty } = view.state.selection;
|
|
149
|
+
const end = pos + node.nodeSize;
|
|
150
|
+
if (empty) {
|
|
151
|
+
return from > pos && from < end;
|
|
152
|
+
}
|
|
153
|
+
return from >= pos && to <= end;
|
|
154
|
+
};
|
|
155
|
+
exports.isSelectionInsideNode = isSelectionInsideNode;
|
package/dist/cjs/versions.js
CHANGED
|
@@ -23,6 +23,7 @@ const style_guide_1 = require("@manuscripts/style-guide");
|
|
|
23
23
|
const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
|
|
24
24
|
const transform_1 = require("@manuscripts/transform");
|
|
25
25
|
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
26
|
+
const xor_1 = __importDefault(require("lodash/xor"));
|
|
26
27
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
27
28
|
const prosemirror_utils_1 = require("prosemirror-utils");
|
|
28
29
|
const DeleteFootnoteDialog_1 = require("../components/views/DeleteFootnoteDialog");
|
|
@@ -32,25 +33,31 @@ const base_node_view_1 = require("./base_node_view");
|
|
|
32
33
|
const creators_1 = require("./creators");
|
|
33
34
|
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
34
35
|
const navigation_utils_1 = require("../lib/navigation-utils");
|
|
36
|
+
const view_1 = require("../lib/view");
|
|
35
37
|
class FootnoteView extends base_node_view_1.BaseNodeView {
|
|
36
38
|
constructor() {
|
|
37
39
|
super(...arguments);
|
|
40
|
+
this.isMenuShown = false;
|
|
41
|
+
this.previousActionsLabels = [];
|
|
38
42
|
this.initialise = () => {
|
|
39
43
|
this.dom = document.createElement('div');
|
|
40
44
|
this.dom.classList.add('footnote');
|
|
41
45
|
this.dom.tabIndex = 0;
|
|
42
46
|
this.contentDOM = document.createElement('div');
|
|
43
47
|
this.contentDOM.classList.add('footnote-text');
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const element = event.target;
|
|
50
|
-
const item = element.closest('.footnote');
|
|
51
|
-
if (item) {
|
|
52
|
-
this.showContextMenu(item, fromKeyboard);
|
|
48
|
+
if (!this.view.editable) {
|
|
49
|
+
const actions = this.getContextMenuActions();
|
|
50
|
+
if (actions.length > 0) {
|
|
51
|
+
this.dom.addEventListener('mousedown', () => this.showContextMenu(actions, true));
|
|
52
|
+
}
|
|
53
53
|
}
|
|
54
|
+
this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => {
|
|
55
|
+
const actions = this.getContextMenuActions();
|
|
56
|
+
if (actions.length > 0) {
|
|
57
|
+
this.showContextMenu(actions, true);
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
this.updateContents();
|
|
54
61
|
};
|
|
55
62
|
this.handleMarkerClick = (e) => {
|
|
56
63
|
e?.preventDefault();
|
|
@@ -134,35 +141,53 @@ class FootnoteView extends base_node_view_1.BaseNodeView {
|
|
|
134
141
|
this.dom.innerHTML = '';
|
|
135
142
|
this.dom.appendChild(marker);
|
|
136
143
|
this.contentDOM && this.dom.appendChild(this.contentDOM);
|
|
144
|
+
const selectionInsideNode = (0, view_1.isSelectionInsideNode)(this.view, this.node, this.getPos());
|
|
145
|
+
const actions = this.getContextMenuActions();
|
|
146
|
+
const hasActions = actions.length > 0;
|
|
147
|
+
const currentLabels = actions.map(({ label }) => label);
|
|
148
|
+
const changedLabels = (0, xor_1.default)(currentLabels, this.previousActionsLabels);
|
|
149
|
+
if (selectionInsideNode &&
|
|
150
|
+
hasActions &&
|
|
151
|
+
(!this.isMenuShown || changedLabels.length > 0)) {
|
|
152
|
+
this.showContextMenu(actions, false);
|
|
153
|
+
this.previousActionsLabels = actions.map(({ label }) => label);
|
|
154
|
+
}
|
|
155
|
+
else if ((!hasActions || !selectionInsideNode) && this.isMenuShown) {
|
|
156
|
+
this.props.popper.destroy();
|
|
157
|
+
this.isMenuShown = false;
|
|
158
|
+
this.previousActionsLabels = [];
|
|
159
|
+
}
|
|
137
160
|
}
|
|
138
161
|
getFootnoteState() {
|
|
139
162
|
const id = this.node.attrs.id;
|
|
140
163
|
const fn = (0, footnotes_1.getFootnotesElementState)(this.view.state, id);
|
|
141
164
|
return { id, fn };
|
|
142
165
|
}
|
|
143
|
-
showContextMenu(
|
|
166
|
+
showContextMenu(actions, autoFocus) {
|
|
167
|
+
this.isMenuShown = true;
|
|
144
168
|
this.props.popper.destroy();
|
|
169
|
+
this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, { actions }, this.node, this.getPos, this.view, ['context-menu', 'footnote-context-menu']);
|
|
170
|
+
this.props.popper.show(this.dom, this.contextMenu, 'right-start', true, [], autoFocus, false);
|
|
171
|
+
}
|
|
172
|
+
getContextMenuActions() {
|
|
145
173
|
const can = this.props.getCapabilities();
|
|
146
174
|
const { id, fn } = this.getFootnoteState();
|
|
147
|
-
const
|
|
148
|
-
actions: [],
|
|
149
|
-
};
|
|
175
|
+
const actions = [];
|
|
150
176
|
if (!fn?.unusedFootnoteIDs.has(id)) {
|
|
151
|
-
|
|
152
|
-
label: 'Go to footnote
|
|
177
|
+
actions.push({
|
|
178
|
+
label: 'Go to footnote Reference',
|
|
153
179
|
action: () => this.handleMarkerClick(),
|
|
154
180
|
icon: 'Scroll',
|
|
155
181
|
});
|
|
156
182
|
}
|
|
157
183
|
if (can.editArticle && !(0, track_changes_plugin_1.isDeleted)(this.node)) {
|
|
158
|
-
|
|
184
|
+
actions.push({
|
|
159
185
|
label: 'Delete',
|
|
160
186
|
action: () => this.handleDeleteClick(),
|
|
161
187
|
icon: 'Delete',
|
|
162
188
|
});
|
|
163
189
|
}
|
|
164
|
-
|
|
165
|
-
this.props.popper.show(element, this.contextMenu, 'right-start', true, [], autoFocus);
|
|
190
|
+
return actions;
|
|
166
191
|
}
|
|
167
192
|
}
|
|
168
193
|
exports.FootnoteView = FootnoteView;
|
|
@@ -27,27 +27,27 @@ const base_node_view_1 = require("./base_node_view");
|
|
|
27
27
|
const creators_1 = require("./creators");
|
|
28
28
|
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
29
29
|
const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
|
|
30
|
+
const navigation_utils_1 = require("../lib/navigation-utils");
|
|
31
|
+
const view_1 = require("../lib/view");
|
|
30
32
|
class GeneralTableFootnoteView extends base_node_view_1.BaseNodeView {
|
|
31
33
|
constructor() {
|
|
32
34
|
super(...arguments);
|
|
35
|
+
this.isMenuShown = false;
|
|
33
36
|
this.initialise = () => {
|
|
34
37
|
this.dom = document.createElement('div');
|
|
35
38
|
this.dom.classList.add('footnote', 'general-table-footnote');
|
|
36
|
-
this.dom.
|
|
39
|
+
this.dom.tabIndex = 0;
|
|
40
|
+
this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => {
|
|
41
|
+
const can = this.props.getCapabilities();
|
|
42
|
+
const canShowMenu = can.editArticle && !(0, track_changes_plugin_1.isDeleted)(this.node);
|
|
43
|
+
if (canShowMenu) {
|
|
44
|
+
this.showContextMenu(true);
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
37
47
|
this.contentDOM = document.createElement('div');
|
|
38
48
|
this.contentDOM.classList.add('footnote-text');
|
|
39
49
|
this.updateContents();
|
|
40
50
|
};
|
|
41
|
-
this.handleClick = (e) => {
|
|
42
|
-
const element = e.target;
|
|
43
|
-
const can = this.props.getCapabilities();
|
|
44
|
-
if (can.editArticle) {
|
|
45
|
-
const item = element.closest('.general-table-footnote');
|
|
46
|
-
if (item) {
|
|
47
|
-
this.showContextMenu(item);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
51
|
this.handleDeleteClick = () => {
|
|
52
52
|
const componentProps = {
|
|
53
53
|
header: 'Delete table general note',
|
|
@@ -80,21 +80,31 @@ class GeneralTableFootnoteView extends base_node_view_1.BaseNodeView {
|
|
|
80
80
|
super.updateContents();
|
|
81
81
|
this.dom.innerHTML = '';
|
|
82
82
|
this.contentDOM && this.dom.appendChild(this.contentDOM);
|
|
83
|
+
const selectionInsideNode = (0, view_1.isSelectionInsideNode)(this.view, this.node, this.getPos());
|
|
84
|
+
const can = this.props.getCapabilities();
|
|
85
|
+
const canShowMenu = can.editArticle && !(0, track_changes_plugin_1.isDeleted)(this.node);
|
|
86
|
+
if (canShowMenu && selectionInsideNode && !this.isMenuShown) {
|
|
87
|
+
this.showContextMenu(false);
|
|
88
|
+
}
|
|
89
|
+
else if ((!canShowMenu || !selectionInsideNode) && this.isMenuShown) {
|
|
90
|
+
this.props.popper.destroy();
|
|
91
|
+
this.isMenuShown = false;
|
|
92
|
+
}
|
|
83
93
|
}
|
|
84
|
-
showContextMenu(
|
|
94
|
+
showContextMenu(autoFocus = false) {
|
|
95
|
+
this.isMenuShown = true;
|
|
85
96
|
this.props.popper.destroy();
|
|
86
97
|
const componentProps = {
|
|
87
|
-
actions: [
|
|
98
|
+
actions: [
|
|
99
|
+
{
|
|
100
|
+
label: 'Delete',
|
|
101
|
+
action: () => this.handleDeleteClick(),
|
|
102
|
+
icon: 'Delete',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
88
105
|
};
|
|
89
|
-
if (!(0, track_changes_plugin_1.isDeleted)(this.node)) {
|
|
90
|
-
componentProps.actions.push({
|
|
91
|
-
label: 'Delete',
|
|
92
|
-
action: () => this.handleDeleteClick(),
|
|
93
|
-
icon: 'Delete',
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
106
|
this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu', 'footnote-context-menu']);
|
|
97
|
-
this.props.popper.show(
|
|
107
|
+
this.props.popper.show(this.dom, this.contextMenu, 'right-start', false, [], autoFocus, false);
|
|
98
108
|
}
|
|
99
109
|
}
|
|
100
110
|
exports.GeneralTableFootnoteView = GeneralTableFootnoteView;
|
package/dist/es/lib/popper.js
CHANGED
|
@@ -19,7 +19,7 @@ export class PopperManager {
|
|
|
19
19
|
constructor() {
|
|
20
20
|
this.isActive = () => !!this.activePopper;
|
|
21
21
|
}
|
|
22
|
-
show(target, contents, placement = 'bottom', showArrow = true, modifiers = [], autoFocus = true, onDestroy = undefined) {
|
|
22
|
+
show(target, contents, placement = 'bottom', showArrow = true, modifiers = [], autoFocus = true, autoCloseOnOutsideClick = true, onDestroy = undefined) {
|
|
23
23
|
this.destroy();
|
|
24
24
|
this.triggerElement = target;
|
|
25
25
|
this.destructionListener = onDestroy;
|
|
@@ -82,9 +82,10 @@ export class PopperManager {
|
|
|
82
82
|
this.destroy();
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
|
-
if (contents.classList.contains('context-menu') ||
|
|
85
|
+
if ((contents.classList.contains('context-menu') ||
|
|
86
86
|
contents.classList.contains('language') ||
|
|
87
|
-
contents.classList.contains('section-category'))
|
|
87
|
+
contents.classList.contains('section-category')) &&
|
|
88
|
+
autoCloseOnOutsideClick) {
|
|
88
89
|
window.addEventListener('click', this.handleDocumentClick);
|
|
89
90
|
}
|
|
90
91
|
});
|
|
@@ -174,7 +174,7 @@ export class HorizontalPositionMenu {
|
|
|
174
174
|
p.props.popper.replaceContent(content);
|
|
175
175
|
}
|
|
176
176
|
else {
|
|
177
|
-
p.props.popper.show(this.positionMenuWrapper, content, 'left', false, [], true, () => {
|
|
177
|
+
p.props.popper.show(this.positionMenuWrapper, content, 'left', false, [], true, true, () => {
|
|
178
178
|
this.menuOpen = false;
|
|
179
179
|
});
|
|
180
180
|
this.menuOpen = true;
|
package/dist/es/lib/view.js
CHANGED
|
@@ -100,3 +100,11 @@ export const saveBibliographyItem = (view, attrs) => {
|
|
|
100
100
|
}
|
|
101
101
|
insertBibliographyItems(view, attrs);
|
|
102
102
|
};
|
|
103
|
+
export const isSelectionInsideNode = (view, node, pos) => {
|
|
104
|
+
const { from, to, empty } = view.state.selection;
|
|
105
|
+
const end = pos + node.nodeSize;
|
|
106
|
+
if (empty) {
|
|
107
|
+
return from > pos && from < end;
|
|
108
|
+
}
|
|
109
|
+
return from >= pos && to <= end;
|
|
110
|
+
};
|
package/dist/es/versions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '3.17.
|
|
1
|
+
export const VERSION = '3.17.1';
|
|
2
2
|
export const MATHJAX_VERSION = '3.2.2';
|
|
@@ -17,6 +17,7 @@ import { ContextMenu } from '@manuscripts/style-guide';
|
|
|
17
17
|
import { isDeleted, isPendingInsert } from '@manuscripts/track-changes-plugin';
|
|
18
18
|
import { schema } from '@manuscripts/transform';
|
|
19
19
|
import isEqual from 'lodash/isEqual';
|
|
20
|
+
import xor from 'lodash/xor';
|
|
20
21
|
import { NodeSelection } from 'prosemirror-state';
|
|
21
22
|
import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils';
|
|
22
23
|
import { DeleteFootnoteDialog, } from '../components/views/DeleteFootnoteDialog';
|
|
@@ -26,25 +27,31 @@ import { BaseNodeView } from './base_node_view';
|
|
|
26
27
|
import { createNodeView } from './creators';
|
|
27
28
|
import ReactSubView from './ReactSubView';
|
|
28
29
|
import { handleEnterKey } from '../lib/navigation-utils';
|
|
30
|
+
import { isSelectionInsideNode } from '../lib/view';
|
|
29
31
|
export class FootnoteView extends BaseNodeView {
|
|
30
32
|
constructor() {
|
|
31
33
|
super(...arguments);
|
|
34
|
+
this.isMenuShown = false;
|
|
35
|
+
this.previousActionsLabels = [];
|
|
32
36
|
this.initialise = () => {
|
|
33
37
|
this.dom = document.createElement('div');
|
|
34
38
|
this.dom.classList.add('footnote');
|
|
35
39
|
this.dom.tabIndex = 0;
|
|
36
40
|
this.contentDOM = document.createElement('div');
|
|
37
41
|
this.contentDOM.classList.add('footnote-text');
|
|
38
|
-
this.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const element = event.target;
|
|
44
|
-
const item = element.closest('.footnote');
|
|
45
|
-
if (item) {
|
|
46
|
-
this.showContextMenu(item, fromKeyboard);
|
|
42
|
+
if (!this.view.editable) {
|
|
43
|
+
const actions = this.getContextMenuActions();
|
|
44
|
+
if (actions.length > 0) {
|
|
45
|
+
this.dom.addEventListener('mousedown', () => this.showContextMenu(actions, true));
|
|
46
|
+
}
|
|
47
47
|
}
|
|
48
|
+
this.dom.addEventListener('keydown', handleEnterKey(() => {
|
|
49
|
+
const actions = this.getContextMenuActions();
|
|
50
|
+
if (actions.length > 0) {
|
|
51
|
+
this.showContextMenu(actions, true);
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
this.updateContents();
|
|
48
55
|
};
|
|
49
56
|
this.handleMarkerClick = (e) => {
|
|
50
57
|
e?.preventDefault();
|
|
@@ -128,35 +135,53 @@ export class FootnoteView extends BaseNodeView {
|
|
|
128
135
|
this.dom.innerHTML = '';
|
|
129
136
|
this.dom.appendChild(marker);
|
|
130
137
|
this.contentDOM && this.dom.appendChild(this.contentDOM);
|
|
138
|
+
const selectionInsideNode = isSelectionInsideNode(this.view, this.node, this.getPos());
|
|
139
|
+
const actions = this.getContextMenuActions();
|
|
140
|
+
const hasActions = actions.length > 0;
|
|
141
|
+
const currentLabels = actions.map(({ label }) => label);
|
|
142
|
+
const changedLabels = xor(currentLabels, this.previousActionsLabels);
|
|
143
|
+
if (selectionInsideNode &&
|
|
144
|
+
hasActions &&
|
|
145
|
+
(!this.isMenuShown || changedLabels.length > 0)) {
|
|
146
|
+
this.showContextMenu(actions, false);
|
|
147
|
+
this.previousActionsLabels = actions.map(({ label }) => label);
|
|
148
|
+
}
|
|
149
|
+
else if ((!hasActions || !selectionInsideNode) && this.isMenuShown) {
|
|
150
|
+
this.props.popper.destroy();
|
|
151
|
+
this.isMenuShown = false;
|
|
152
|
+
this.previousActionsLabels = [];
|
|
153
|
+
}
|
|
131
154
|
}
|
|
132
155
|
getFootnoteState() {
|
|
133
156
|
const id = this.node.attrs.id;
|
|
134
157
|
const fn = getFootnotesElementState(this.view.state, id);
|
|
135
158
|
return { id, fn };
|
|
136
159
|
}
|
|
137
|
-
showContextMenu(
|
|
160
|
+
showContextMenu(actions, autoFocus) {
|
|
161
|
+
this.isMenuShown = true;
|
|
138
162
|
this.props.popper.destroy();
|
|
163
|
+
this.contextMenu = ReactSubView(this.props, ContextMenu, { actions }, this.node, this.getPos, this.view, ['context-menu', 'footnote-context-menu']);
|
|
164
|
+
this.props.popper.show(this.dom, this.contextMenu, 'right-start', true, [], autoFocus, false);
|
|
165
|
+
}
|
|
166
|
+
getContextMenuActions() {
|
|
139
167
|
const can = this.props.getCapabilities();
|
|
140
168
|
const { id, fn } = this.getFootnoteState();
|
|
141
|
-
const
|
|
142
|
-
actions: [],
|
|
143
|
-
};
|
|
169
|
+
const actions = [];
|
|
144
170
|
if (!fn?.unusedFootnoteIDs.has(id)) {
|
|
145
|
-
|
|
146
|
-
label: 'Go to footnote
|
|
171
|
+
actions.push({
|
|
172
|
+
label: 'Go to footnote Reference',
|
|
147
173
|
action: () => this.handleMarkerClick(),
|
|
148
174
|
icon: 'Scroll',
|
|
149
175
|
});
|
|
150
176
|
}
|
|
151
177
|
if (can.editArticle && !isDeleted(this.node)) {
|
|
152
|
-
|
|
178
|
+
actions.push({
|
|
153
179
|
label: 'Delete',
|
|
154
180
|
action: () => this.handleDeleteClick(),
|
|
155
181
|
icon: 'Delete',
|
|
156
182
|
});
|
|
157
183
|
}
|
|
158
|
-
|
|
159
|
-
this.props.popper.show(element, this.contextMenu, 'right-start', true, [], autoFocus);
|
|
184
|
+
return actions;
|
|
160
185
|
}
|
|
161
186
|
}
|
|
162
187
|
const getEffectiveChildCount = (node) => {
|
|
@@ -21,27 +21,27 @@ import { BaseNodeView } from './base_node_view';
|
|
|
21
21
|
import { createNodeView } from './creators';
|
|
22
22
|
import ReactSubView from './ReactSubView';
|
|
23
23
|
import { isDeleted, isPendingInsert } from '@manuscripts/track-changes-plugin';
|
|
24
|
+
import { handleEnterKey } from '../lib/navigation-utils';
|
|
25
|
+
import { isSelectionInsideNode } from '../lib/view';
|
|
24
26
|
export class GeneralTableFootnoteView extends BaseNodeView {
|
|
25
27
|
constructor() {
|
|
26
28
|
super(...arguments);
|
|
29
|
+
this.isMenuShown = false;
|
|
27
30
|
this.initialise = () => {
|
|
28
31
|
this.dom = document.createElement('div');
|
|
29
32
|
this.dom.classList.add('footnote', 'general-table-footnote');
|
|
30
|
-
this.dom.
|
|
33
|
+
this.dom.tabIndex = 0;
|
|
34
|
+
this.dom.addEventListener('keydown', handleEnterKey(() => {
|
|
35
|
+
const can = this.props.getCapabilities();
|
|
36
|
+
const canShowMenu = can.editArticle && !isDeleted(this.node);
|
|
37
|
+
if (canShowMenu) {
|
|
38
|
+
this.showContextMenu(true);
|
|
39
|
+
}
|
|
40
|
+
}));
|
|
31
41
|
this.contentDOM = document.createElement('div');
|
|
32
42
|
this.contentDOM.classList.add('footnote-text');
|
|
33
43
|
this.updateContents();
|
|
34
44
|
};
|
|
35
|
-
this.handleClick = (e) => {
|
|
36
|
-
const element = e.target;
|
|
37
|
-
const can = this.props.getCapabilities();
|
|
38
|
-
if (can.editArticle) {
|
|
39
|
-
const item = element.closest('.general-table-footnote');
|
|
40
|
-
if (item) {
|
|
41
|
-
this.showContextMenu(item);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
45
|
this.handleDeleteClick = () => {
|
|
46
46
|
const componentProps = {
|
|
47
47
|
header: 'Delete table general note',
|
|
@@ -74,21 +74,31 @@ export class GeneralTableFootnoteView extends BaseNodeView {
|
|
|
74
74
|
super.updateContents();
|
|
75
75
|
this.dom.innerHTML = '';
|
|
76
76
|
this.contentDOM && this.dom.appendChild(this.contentDOM);
|
|
77
|
+
const selectionInsideNode = isSelectionInsideNode(this.view, this.node, this.getPos());
|
|
78
|
+
const can = this.props.getCapabilities();
|
|
79
|
+
const canShowMenu = can.editArticle && !isDeleted(this.node);
|
|
80
|
+
if (canShowMenu && selectionInsideNode && !this.isMenuShown) {
|
|
81
|
+
this.showContextMenu(false);
|
|
82
|
+
}
|
|
83
|
+
else if ((!canShowMenu || !selectionInsideNode) && this.isMenuShown) {
|
|
84
|
+
this.props.popper.destroy();
|
|
85
|
+
this.isMenuShown = false;
|
|
86
|
+
}
|
|
77
87
|
}
|
|
78
|
-
showContextMenu(
|
|
88
|
+
showContextMenu(autoFocus = false) {
|
|
89
|
+
this.isMenuShown = true;
|
|
79
90
|
this.props.popper.destroy();
|
|
80
91
|
const componentProps = {
|
|
81
|
-
actions: [
|
|
92
|
+
actions: [
|
|
93
|
+
{
|
|
94
|
+
label: 'Delete',
|
|
95
|
+
action: () => this.handleDeleteClick(),
|
|
96
|
+
icon: 'Delete',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
82
99
|
};
|
|
83
|
-
if (!isDeleted(this.node)) {
|
|
84
|
-
componentProps.actions.push({
|
|
85
|
-
label: 'Delete',
|
|
86
|
-
action: () => this.handleDeleteClick(),
|
|
87
|
-
icon: 'Delete',
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
100
|
this.contextMenu = ReactSubView(this.props, ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu', 'footnote-context-menu']);
|
|
91
|
-
this.props.popper.show(
|
|
101
|
+
this.props.popper.show(this.dom, this.contextMenu, 'right-start', false, [], autoFocus, false);
|
|
92
102
|
}
|
|
93
103
|
}
|
|
94
104
|
export default createNodeView(GeneralTableFootnoteView);
|
|
@@ -20,7 +20,7 @@ export declare class PopperManager {
|
|
|
20
20
|
private triggerElement?;
|
|
21
21
|
private container?;
|
|
22
22
|
private destructionListener?;
|
|
23
|
-
show(target: Element, contents: HTMLElement, placement?: Placement, showArrow?: boolean, modifiers?: Array<Partial<StrictModifiers>>, autoFocus?: boolean, onDestroy?: ((i: Instance) => void) | undefined): void;
|
|
23
|
+
show(target: Element, contents: HTMLElement, placement?: Placement, showArrow?: boolean, modifiers?: Array<Partial<StrictModifiers>>, autoFocus?: boolean, autoCloseOnOutsideClick?: boolean, onDestroy?: ((i: Instance) => void) | undefined): void;
|
|
24
24
|
destroy(): void;
|
|
25
25
|
getContainer(): HTMLElement | undefined;
|
|
26
26
|
update(): void;
|
package/dist/types/lib/view.d.ts
CHANGED
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { BibliographyItemAttrs, ManuscriptEditorView, ManuscriptNodeType } from '@manuscripts/transform';
|
|
16
|
+
import { BibliographyItemAttrs, ManuscriptEditorView, ManuscriptNode, ManuscriptNodeType } from '@manuscripts/transform';
|
|
17
17
|
import { Attrs } from 'prosemirror-model';
|
|
18
18
|
import * as utils from 'prosemirror-utils';
|
|
19
|
+
import { EditorView } from 'prosemirror-view';
|
|
19
20
|
export declare const findChildByID: (view: ManuscriptEditorView, id: string) => utils.NodeWithPos | undefined;
|
|
20
21
|
export declare const findChildByType: (view: ManuscriptEditorView, type: ManuscriptNodeType) => utils.NodeWithPos | undefined;
|
|
21
22
|
export declare const findChildrenByType: (view: ManuscriptEditorView, type: ManuscriptNodeType) => utils.NodeWithPos[];
|
|
@@ -24,3 +25,4 @@ export declare const updateNodeAttrs: (view: ManuscriptEditorView, type: Manuscr
|
|
|
24
25
|
export declare const deleteNode: (view: ManuscriptEditorView, id: string) => void;
|
|
25
26
|
export declare const insertBibliographyItems: (view: ManuscriptEditorView, items: BibliographyItemAttrs[]) => void;
|
|
26
27
|
export declare const saveBibliographyItem: (view: ManuscriptEditorView, attrs: BibliographyItemAttrs[]) => void;
|
|
28
|
+
export declare const isSelectionInsideNode: (view: EditorView, node: ManuscriptNode, pos: number) => boolean;
|
package/dist/types/versions.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "3.17.
|
|
1
|
+
export declare const VERSION = "3.17.1";
|
|
2
2
|
export declare const MATHJAX_VERSION = "3.2.2";
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { ContextMenuProps } from '@manuscripts/style-guide';
|
|
16
17
|
import { FootnoteNode } from '@manuscripts/transform';
|
|
17
18
|
import { Transaction } from 'prosemirror-state';
|
|
18
19
|
import { Trackable } from '../types';
|
|
@@ -20,14 +21,16 @@ import { BaseNodeView } from './base_node_view';
|
|
|
20
21
|
export declare class FootnoteView extends BaseNodeView<Trackable<FootnoteNode>> {
|
|
21
22
|
dialog: HTMLElement;
|
|
22
23
|
contextMenu: HTMLDivElement;
|
|
24
|
+
isMenuShown: boolean;
|
|
25
|
+
previousActionsLabels: string[];
|
|
23
26
|
initialise: () => void;
|
|
24
27
|
updateContents(): void;
|
|
25
28
|
getFootnoteState(): {
|
|
26
29
|
id: string;
|
|
27
30
|
fn: import("../plugins/footnotes").FootnotesElementState | undefined;
|
|
28
31
|
};
|
|
29
|
-
showContextMenu(
|
|
30
|
-
|
|
32
|
+
showContextMenu(actions: ContextMenuProps['actions'], autoFocus: boolean): void;
|
|
33
|
+
getContextMenuActions(): import("@manuscripts/style-guide").Actions[];
|
|
31
34
|
handleMarkerClick: (e?: Event) => void;
|
|
32
35
|
handleDeleteClick: (e?: Event) => void;
|
|
33
36
|
handleDelete: () => void;
|
|
@@ -19,10 +19,10 @@ import { BaseNodeView } from './base_node_view';
|
|
|
19
19
|
export declare class GeneralTableFootnoteView extends BaseNodeView<Trackable<GeneralTableFootnoteNode>> {
|
|
20
20
|
dialog: HTMLElement;
|
|
21
21
|
contextMenu: HTMLDivElement;
|
|
22
|
+
isMenuShown: boolean;
|
|
22
23
|
initialise: () => void;
|
|
23
24
|
updateContents(): void;
|
|
24
|
-
|
|
25
|
-
showContextMenu(element: HTMLElement): void;
|
|
25
|
+
showContextMenu(autoFocus?: boolean): void;
|
|
26
26
|
handleDeleteClick: () => void;
|
|
27
27
|
handleDelete: () => void;
|
|
28
28
|
}
|
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": "3.17.
|
|
4
|
+
"version": "3.17.1",
|
|
5
5
|
"repository": "github:Atypon-OpenSource/manuscripts-body-editor",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "dist/cjs",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@iarna/word-count": "1.1.2",
|
|
44
44
|
"@manuscripts/style-guide": "3.7.1",
|
|
45
45
|
"@manuscripts/track-changes-plugin": "2.4.0",
|
|
46
|
-
"@manuscripts/transform": "4.5.
|
|
46
|
+
"@manuscripts/transform": "4.5.2",
|
|
47
47
|
"@popperjs/core": "2.11.8",
|
|
48
48
|
"citeproc": "2.4.63",
|
|
49
49
|
"codemirror": "5.65.19",
|
package/src/lib/popper.ts
CHANGED
|
@@ -36,6 +36,7 @@ export class PopperManager {
|
|
|
36
36
|
showArrow = true,
|
|
37
37
|
modifiers: Array<Partial<StrictModifiers>> = [],
|
|
38
38
|
autoFocus = true,
|
|
39
|
+
autoCloseOnOutsideClick = true,
|
|
39
40
|
onDestroy: ((i: Instance) => void) | undefined = undefined
|
|
40
41
|
) {
|
|
41
42
|
// destroy any existing popper first
|
|
@@ -114,9 +115,10 @@ export class PopperManager {
|
|
|
114
115
|
// add EventListener for checking if click was done outside of editor
|
|
115
116
|
// only if popper has class 'context-menu'
|
|
116
117
|
if (
|
|
117
|
-
contents.classList.contains('context-menu') ||
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
(contents.classList.contains('context-menu') ||
|
|
119
|
+
contents.classList.contains('language') ||
|
|
120
|
+
contents.classList.contains('section-category')) &&
|
|
121
|
+
autoCloseOnOutsideClick
|
|
120
122
|
) {
|
|
121
123
|
window.addEventListener('click', this.handleDocumentClick)
|
|
122
124
|
}
|
package/src/lib/position-menu.ts
CHANGED
package/src/lib/view.ts
CHANGED
|
@@ -27,6 +27,7 @@ import * as utils from 'prosemirror-utils'
|
|
|
27
27
|
|
|
28
28
|
import { isHidden } from './track-changes-utils'
|
|
29
29
|
import { sanitizeAttrsChange } from '@manuscripts/track-changes-plugin'
|
|
30
|
+
import { EditorView } from 'prosemirror-view'
|
|
30
31
|
|
|
31
32
|
const metaNodeTypes = [
|
|
32
33
|
schema.nodes.bibliography_item,
|
|
@@ -163,3 +164,19 @@ export const saveBibliographyItem = (
|
|
|
163
164
|
|
|
164
165
|
insertBibliographyItems(view, attrs)
|
|
165
166
|
}
|
|
167
|
+
|
|
168
|
+
export const isSelectionInsideNode = (
|
|
169
|
+
view: EditorView,
|
|
170
|
+
node: ManuscriptNode,
|
|
171
|
+
pos: number
|
|
172
|
+
) => {
|
|
173
|
+
const { from, to, empty } = view.state.selection
|
|
174
|
+
const end = pos + node.nodeSize
|
|
175
|
+
|
|
176
|
+
// Treat a cursor as "inside" only when it is strictly within the node range.
|
|
177
|
+
if (empty) {
|
|
178
|
+
return from > pos && from < end
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return from >= pos && to <= end
|
|
182
|
+
}
|
package/src/versions.ts
CHANGED
package/src/views/footnote.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { isDeleted, isPendingInsert } from '@manuscripts/track-changes-plugin'
|
|
|
19
19
|
import { FootnoteNode, ManuscriptNode, schema } from '@manuscripts/transform'
|
|
20
20
|
|
|
21
21
|
import isEqual from 'lodash/isEqual'
|
|
22
|
+
import xor from 'lodash/xor'
|
|
22
23
|
import { NodeSelection, Transaction } from 'prosemirror-state'
|
|
23
24
|
import { findParentNodeOfTypeClosestToPos } from 'prosemirror-utils'
|
|
24
25
|
|
|
@@ -33,10 +34,13 @@ import { BaseNodeView } from './base_node_view'
|
|
|
33
34
|
import { createNodeView } from './creators'
|
|
34
35
|
import ReactSubView from './ReactSubView'
|
|
35
36
|
import { handleEnterKey } from '../lib/navigation-utils'
|
|
37
|
+
import { isSelectionInsideNode } from '../lib/view'
|
|
36
38
|
|
|
37
39
|
export class FootnoteView extends BaseNodeView<Trackable<FootnoteNode>> {
|
|
38
40
|
dialog: HTMLElement
|
|
39
41
|
contextMenu: HTMLDivElement
|
|
42
|
+
isMenuShown: boolean = false
|
|
43
|
+
previousActionsLabels: string[] = []
|
|
40
44
|
|
|
41
45
|
public initialise = () => {
|
|
42
46
|
this.dom = document.createElement('div')
|
|
@@ -44,10 +48,24 @@ export class FootnoteView extends BaseNodeView<Trackable<FootnoteNode>> {
|
|
|
44
48
|
this.dom.tabIndex = 0
|
|
45
49
|
this.contentDOM = document.createElement('div')
|
|
46
50
|
this.contentDOM.classList.add('footnote-text')
|
|
47
|
-
this.
|
|
51
|
+
if (!this.view.editable) {
|
|
52
|
+
// when the editor is in the viewing mode we can't depend on the selection to show context-menu so we use mousedown
|
|
53
|
+
// as in that case will not have the same listener from prosemirror-view to interfere with it
|
|
54
|
+
const actions = this.getContextMenuActions()
|
|
55
|
+
if (actions.length > 0) {
|
|
56
|
+
this.dom.addEventListener('mousedown', () =>
|
|
57
|
+
this.showContextMenu(actions, true)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
48
61
|
this.dom.addEventListener(
|
|
49
62
|
'keydown',
|
|
50
|
-
handleEnterKey((
|
|
63
|
+
handleEnterKey(() => {
|
|
64
|
+
const actions = this.getContextMenuActions()
|
|
65
|
+
if (actions.length > 0) {
|
|
66
|
+
this.showContextMenu(actions, true)
|
|
67
|
+
}
|
|
68
|
+
})
|
|
51
69
|
)
|
|
52
70
|
this.updateContents()
|
|
53
71
|
}
|
|
@@ -73,6 +91,29 @@ export class FootnoteView extends BaseNodeView<Trackable<FootnoteNode>> {
|
|
|
73
91
|
this.dom.innerHTML = ''
|
|
74
92
|
this.dom.appendChild(marker)
|
|
75
93
|
this.contentDOM && this.dom.appendChild(this.contentDOM)
|
|
94
|
+
|
|
95
|
+
const selectionInsideNode = isSelectionInsideNode(
|
|
96
|
+
this.view,
|
|
97
|
+
this.node,
|
|
98
|
+
this.getPos()
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
const actions = this.getContextMenuActions()
|
|
102
|
+
const hasActions = actions.length > 0
|
|
103
|
+
const currentLabels = actions.map(({ label }) => label)
|
|
104
|
+
const changedLabels = xor(currentLabels, this.previousActionsLabels)
|
|
105
|
+
if (
|
|
106
|
+
selectionInsideNode &&
|
|
107
|
+
hasActions &&
|
|
108
|
+
(!this.isMenuShown || changedLabels.length > 0)
|
|
109
|
+
) {
|
|
110
|
+
this.showContextMenu(actions, false)
|
|
111
|
+
this.previousActionsLabels = actions.map(({ label }) => label)
|
|
112
|
+
} else if ((!hasActions || !selectionInsideNode) && this.isMenuShown) {
|
|
113
|
+
this.props.popper.destroy()
|
|
114
|
+
this.isMenuShown = false
|
|
115
|
+
this.previousActionsLabels = []
|
|
116
|
+
}
|
|
76
117
|
}
|
|
77
118
|
|
|
78
119
|
getFootnoteState() {
|
|
@@ -81,55 +122,50 @@ export class FootnoteView extends BaseNodeView<Trackable<FootnoteNode>> {
|
|
|
81
122
|
return { id, fn }
|
|
82
123
|
}
|
|
83
124
|
|
|
84
|
-
showContextMenu(
|
|
125
|
+
showContextMenu(actions: ContextMenuProps['actions'], autoFocus: boolean) {
|
|
126
|
+
this.isMenuShown = true
|
|
85
127
|
this.props.popper.destroy()
|
|
86
|
-
|
|
87
|
-
const can = this.props.getCapabilities()
|
|
88
|
-
const { id, fn } = this.getFootnoteState()
|
|
89
|
-
|
|
90
|
-
const componentProps: ContextMenuProps = {
|
|
91
|
-
actions: [],
|
|
92
|
-
}
|
|
93
|
-
if (!fn?.unusedFootnoteIDs.has(id)) {
|
|
94
|
-
componentProps.actions.push({
|
|
95
|
-
label: 'Go to footnote Refernce',
|
|
96
|
-
action: () => this.handleMarkerClick(),
|
|
97
|
-
icon: 'Scroll',
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
if (can.editArticle && !isDeleted(this.node)) {
|
|
101
|
-
componentProps.actions.push({
|
|
102
|
-
label: 'Delete',
|
|
103
|
-
action: () => this.handleDeleteClick(),
|
|
104
|
-
icon: 'Delete',
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
|
|
108
128
|
this.contextMenu = ReactSubView(
|
|
109
129
|
this.props,
|
|
110
130
|
ContextMenu,
|
|
111
|
-
|
|
131
|
+
{ actions },
|
|
112
132
|
this.node,
|
|
113
133
|
this.getPos,
|
|
114
134
|
this.view,
|
|
115
135
|
['context-menu', 'footnote-context-menu']
|
|
116
136
|
)
|
|
117
137
|
this.props.popper.show(
|
|
118
|
-
|
|
138
|
+
this.dom,
|
|
119
139
|
this.contextMenu,
|
|
120
140
|
'right-start',
|
|
121
141
|
true,
|
|
122
142
|
[],
|
|
123
|
-
autoFocus
|
|
143
|
+
autoFocus,
|
|
144
|
+
false
|
|
124
145
|
)
|
|
125
146
|
}
|
|
126
147
|
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
getContextMenuActions() {
|
|
149
|
+
const can = this.props.getCapabilities()
|
|
150
|
+
const { id, fn } = this.getFootnoteState()
|
|
151
|
+
const actions: ContextMenuProps['actions'] = []
|
|
152
|
+
|
|
153
|
+
if (!fn?.unusedFootnoteIDs.has(id)) {
|
|
154
|
+
actions.push({
|
|
155
|
+
label: 'Go to footnote Reference',
|
|
156
|
+
action: () => this.handleMarkerClick(),
|
|
157
|
+
icon: 'Scroll',
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
if (can.editArticle && !isDeleted(this.node)) {
|
|
161
|
+
actions.push({
|
|
162
|
+
label: 'Delete',
|
|
163
|
+
action: () => this.handleDeleteClick(),
|
|
164
|
+
icon: 'Delete',
|
|
165
|
+
})
|
|
132
166
|
}
|
|
167
|
+
|
|
168
|
+
return actions
|
|
133
169
|
}
|
|
134
170
|
|
|
135
171
|
handleMarkerClick = (e?: Event) => {
|
|
@@ -30,17 +30,30 @@ import { BaseNodeView } from './base_node_view'
|
|
|
30
30
|
import { createNodeView } from './creators'
|
|
31
31
|
import ReactSubView from './ReactSubView'
|
|
32
32
|
import { isDeleted, isPendingInsert } from '@manuscripts/track-changes-plugin'
|
|
33
|
+
import { handleEnterKey } from '../lib/navigation-utils'
|
|
34
|
+
import { isSelectionInsideNode } from '../lib/view'
|
|
33
35
|
|
|
34
36
|
export class GeneralTableFootnoteView extends BaseNodeView<
|
|
35
37
|
Trackable<GeneralTableFootnoteNode>
|
|
36
38
|
> {
|
|
37
39
|
dialog: HTMLElement
|
|
38
40
|
contextMenu: HTMLDivElement
|
|
41
|
+
isMenuShown: boolean = false
|
|
39
42
|
|
|
40
43
|
public initialise = () => {
|
|
41
44
|
this.dom = document.createElement('div')
|
|
42
45
|
this.dom.classList.add('footnote', 'general-table-footnote')
|
|
43
|
-
this.dom.
|
|
46
|
+
this.dom.tabIndex = 0
|
|
47
|
+
this.dom.addEventListener(
|
|
48
|
+
'keydown',
|
|
49
|
+
handleEnterKey(() => {
|
|
50
|
+
const can = this.props.getCapabilities()
|
|
51
|
+
const canShowMenu = can.editArticle && !isDeleted(this.node)
|
|
52
|
+
if (canShowMenu) {
|
|
53
|
+
this.showContextMenu(true)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
)
|
|
44
57
|
this.contentDOM = document.createElement('div')
|
|
45
58
|
this.contentDOM.classList.add('footnote-text')
|
|
46
59
|
this.updateContents()
|
|
@@ -50,32 +63,34 @@ export class GeneralTableFootnoteView extends BaseNodeView<
|
|
|
50
63
|
super.updateContents()
|
|
51
64
|
this.dom.innerHTML = ''
|
|
52
65
|
this.contentDOM && this.dom.appendChild(this.contentDOM)
|
|
53
|
-
}
|
|
54
66
|
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
const selectionInsideNode = isSelectionInsideNode(
|
|
68
|
+
this.view,
|
|
69
|
+
this.node,
|
|
70
|
+
this.getPos()
|
|
71
|
+
)
|
|
57
72
|
const can = this.props.getCapabilities()
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
const canShowMenu = can.editArticle && !isDeleted(this.node)
|
|
74
|
+
if (canShowMenu && selectionInsideNode && !this.isMenuShown) {
|
|
75
|
+
this.showContextMenu(false)
|
|
76
|
+
} else if ((!canShowMenu || !selectionInsideNode) && this.isMenuShown) {
|
|
77
|
+
this.props.popper.destroy()
|
|
78
|
+
this.isMenuShown = false
|
|
64
79
|
}
|
|
65
80
|
}
|
|
66
81
|
|
|
67
|
-
showContextMenu(
|
|
82
|
+
showContextMenu(autoFocus = false) {
|
|
83
|
+
this.isMenuShown = true
|
|
68
84
|
this.props.popper.destroy()
|
|
69
85
|
|
|
70
86
|
const componentProps: ContextMenuProps = {
|
|
71
|
-
actions: [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
})
|
|
87
|
+
actions: [
|
|
88
|
+
{
|
|
89
|
+
label: 'Delete',
|
|
90
|
+
action: () => this.handleDeleteClick(),
|
|
91
|
+
icon: 'Delete',
|
|
92
|
+
},
|
|
93
|
+
],
|
|
79
94
|
}
|
|
80
95
|
|
|
81
96
|
this.contextMenu = ReactSubView(
|
|
@@ -87,7 +102,15 @@ export class GeneralTableFootnoteView extends BaseNodeView<
|
|
|
87
102
|
this.view,
|
|
88
103
|
['context-menu', 'footnote-context-menu']
|
|
89
104
|
)
|
|
90
|
-
this.props.popper.show(
|
|
105
|
+
this.props.popper.show(
|
|
106
|
+
this.dom,
|
|
107
|
+
this.contextMenu,
|
|
108
|
+
'right-start',
|
|
109
|
+
false,
|
|
110
|
+
[],
|
|
111
|
+
autoFocus,
|
|
112
|
+
false
|
|
113
|
+
)
|
|
91
114
|
}
|
|
92
115
|
|
|
93
116
|
handleDeleteClick = () => {
|