@manuscripts/body-editor 3.17.0 → 3.17.2
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/menus.js +1 -37
- 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/menus.js +1 -37
- 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/menus.tsx +1 -40
- 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/menus.js
CHANGED
|
@@ -333,41 +333,6 @@ const getEditorMenus = (editor) => {
|
|
|
333
333
|
{
|
|
334
334
|
role: 'separator',
|
|
335
335
|
},
|
|
336
|
-
{
|
|
337
|
-
id: 'insert-citation',
|
|
338
|
-
label: 'Citation',
|
|
339
|
-
shortcut: {
|
|
340
|
-
mac: 'Option+CommandOrControl+C',
|
|
341
|
-
pc: 'CommandOrControl+Option+C',
|
|
342
|
-
},
|
|
343
|
-
isEnabled: (0, utils_1.isEditAllowed)(state) &&
|
|
344
|
-
isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.citation)),
|
|
345
|
-
run: doCommand(commands_1.insertInlineCitation),
|
|
346
|
-
isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.citation),
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
id: 'insert-cross-reference',
|
|
350
|
-
label: 'Cross-reference',
|
|
351
|
-
shortcut: {
|
|
352
|
-
mac: 'Option+CommandOrControl+R',
|
|
353
|
-
pc: 'CommandOrControl+Option+R',
|
|
354
|
-
},
|
|
355
|
-
isEnabled: (0, utils_1.isEditAllowed)(state) && isCommandValid(commands_1.canInsertCrossReference),
|
|
356
|
-
run: doCommand(commands_1.insertCrossReference),
|
|
357
|
-
isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.cross_reference),
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
id: 'insert-footnote',
|
|
361
|
-
label: 'Footnote',
|
|
362
|
-
shortcut: {
|
|
363
|
-
mac: 'Option+CommandOrControl+F',
|
|
364
|
-
pc: 'CommandOrControl+Option+F',
|
|
365
|
-
},
|
|
366
|
-
isEnabled: (0, utils_1.isEditAllowed)(state) &&
|
|
367
|
-
isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.inline_footnote)),
|
|
368
|
-
run: doCommand(commands_1.insertInlineFootnote),
|
|
369
|
-
isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.inline_footnote),
|
|
370
|
-
},
|
|
371
336
|
{
|
|
372
337
|
id: 'insert-special-character',
|
|
373
338
|
label: 'Special Characters',
|
|
@@ -608,8 +573,7 @@ const getEditorMenus = (editor) => {
|
|
|
608
573
|
mac: 'Option+CommandOrControl+R',
|
|
609
574
|
pc: 'CommandOrControl+Option+R',
|
|
610
575
|
},
|
|
611
|
-
isEnabled: (0, utils_1.isEditAllowed)(state) &&
|
|
612
|
-
isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.cross_reference)),
|
|
576
|
+
isEnabled: (0, utils_1.isEditAllowed)(state) && isCommandValid(commands_1.canInsertCrossReference),
|
|
613
577
|
run: doCommand(commands_1.insertCrossReference),
|
|
614
578
|
isHidden: !(0, template_1.templateAllows)(state, transform_1.schema.nodes.cross_reference),
|
|
615
579
|
},
|
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/menus.js
CHANGED
|
@@ -330,41 +330,6 @@ export const getEditorMenus = (editor) => {
|
|
|
330
330
|
{
|
|
331
331
|
role: 'separator',
|
|
332
332
|
},
|
|
333
|
-
{
|
|
334
|
-
id: 'insert-citation',
|
|
335
|
-
label: 'Citation',
|
|
336
|
-
shortcut: {
|
|
337
|
-
mac: 'Option+CommandOrControl+C',
|
|
338
|
-
pc: 'CommandOrControl+Option+C',
|
|
339
|
-
},
|
|
340
|
-
isEnabled: isEditAllowed(state) &&
|
|
341
|
-
isCommandValid(canInsert(schema.nodes.citation)),
|
|
342
|
-
run: doCommand(insertInlineCitation),
|
|
343
|
-
isHidden: !templateAllows(state, schema.nodes.citation),
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
id: 'insert-cross-reference',
|
|
347
|
-
label: 'Cross-reference',
|
|
348
|
-
shortcut: {
|
|
349
|
-
mac: 'Option+CommandOrControl+R',
|
|
350
|
-
pc: 'CommandOrControl+Option+R',
|
|
351
|
-
},
|
|
352
|
-
isEnabled: isEditAllowed(state) && isCommandValid(canInsertCrossReference),
|
|
353
|
-
run: doCommand(insertCrossReference),
|
|
354
|
-
isHidden: !templateAllows(state, schema.nodes.cross_reference),
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
id: 'insert-footnote',
|
|
358
|
-
label: 'Footnote',
|
|
359
|
-
shortcut: {
|
|
360
|
-
mac: 'Option+CommandOrControl+F',
|
|
361
|
-
pc: 'CommandOrControl+Option+F',
|
|
362
|
-
},
|
|
363
|
-
isEnabled: isEditAllowed(state) &&
|
|
364
|
-
isCommandValid(canInsert(schema.nodes.inline_footnote)),
|
|
365
|
-
run: doCommand(insertInlineFootnote),
|
|
366
|
-
isHidden: !templateAllows(state, schema.nodes.inline_footnote),
|
|
367
|
-
},
|
|
368
333
|
{
|
|
369
334
|
id: 'insert-special-character',
|
|
370
335
|
label: 'Special Characters',
|
|
@@ -605,8 +570,7 @@ export const getEditorMenus = (editor) => {
|
|
|
605
570
|
mac: 'Option+CommandOrControl+R',
|
|
606
571
|
pc: 'CommandOrControl+Option+R',
|
|
607
572
|
},
|
|
608
|
-
isEnabled: isEditAllowed(state) &&
|
|
609
|
-
isCommandValid(canInsert(schema.nodes.cross_reference)),
|
|
573
|
+
isEnabled: isEditAllowed(state) && isCommandValid(canInsertCrossReference),
|
|
610
574
|
run: doCommand(insertCrossReference),
|
|
611
575
|
isHidden: !templateAllows(state, schema.nodes.cross_reference),
|
|
612
576
|
},
|
package/dist/es/versions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '3.17.
|
|
1
|
+
export const VERSION = '3.17.2';
|
|
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.2";
|
|
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.2",
|
|
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/menus.tsx
CHANGED
|
@@ -401,44 +401,6 @@ export const getEditorMenus = (
|
|
|
401
401
|
{
|
|
402
402
|
role: 'separator',
|
|
403
403
|
},
|
|
404
|
-
{
|
|
405
|
-
id: 'insert-citation',
|
|
406
|
-
label: 'Citation',
|
|
407
|
-
shortcut: {
|
|
408
|
-
mac: 'Option+CommandOrControl+C',
|
|
409
|
-
pc: 'CommandOrControl+Option+C',
|
|
410
|
-
},
|
|
411
|
-
isEnabled:
|
|
412
|
-
isEditAllowed(state) &&
|
|
413
|
-
isCommandValid(canInsert(schema.nodes.citation)),
|
|
414
|
-
run: doCommand(insertInlineCitation),
|
|
415
|
-
isHidden: !templateAllows(state, schema.nodes.citation),
|
|
416
|
-
},
|
|
417
|
-
{
|
|
418
|
-
id: 'insert-cross-reference',
|
|
419
|
-
label: 'Cross-reference',
|
|
420
|
-
shortcut: {
|
|
421
|
-
mac: 'Option+CommandOrControl+R',
|
|
422
|
-
pc: 'CommandOrControl+Option+R',
|
|
423
|
-
},
|
|
424
|
-
isEnabled:
|
|
425
|
-
isEditAllowed(state) && isCommandValid(canInsertCrossReference),
|
|
426
|
-
run: doCommand(insertCrossReference),
|
|
427
|
-
isHidden: !templateAllows(state, schema.nodes.cross_reference),
|
|
428
|
-
},
|
|
429
|
-
{
|
|
430
|
-
id: 'insert-footnote',
|
|
431
|
-
label: 'Footnote',
|
|
432
|
-
shortcut: {
|
|
433
|
-
mac: 'Option+CommandOrControl+F',
|
|
434
|
-
pc: 'CommandOrControl+Option+F',
|
|
435
|
-
},
|
|
436
|
-
isEnabled:
|
|
437
|
-
isEditAllowed(state) &&
|
|
438
|
-
isCommandValid(canInsert(schema.nodes.inline_footnote)),
|
|
439
|
-
run: doCommand(insertInlineFootnote),
|
|
440
|
-
isHidden: !templateAllows(state, schema.nodes.inline_footnote),
|
|
441
|
-
},
|
|
442
404
|
{
|
|
443
405
|
id: 'insert-special-character',
|
|
444
406
|
label: 'Special Characters',
|
|
@@ -698,8 +660,7 @@ export const getEditorMenus = (
|
|
|
698
660
|
pc: 'CommandOrControl+Option+R',
|
|
699
661
|
},
|
|
700
662
|
isEnabled:
|
|
701
|
-
isEditAllowed(state) &&
|
|
702
|
-
isCommandValid(canInsert(schema.nodes.cross_reference)),
|
|
663
|
+
isEditAllowed(state) && isCommandValid(canInsertCrossReference),
|
|
703
664
|
run: doCommand(insertCrossReference),
|
|
704
665
|
isHidden: !templateAllows(state, schema.nodes.cross_reference),
|
|
705
666
|
},
|
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 = () => {
|