@manuscripts/body-editor 2.7.28 → 2.7.30-LEAN-4096.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.
- package/dist/cjs/components/affiliations/AffiliationItem.js +2 -2
- package/dist/cjs/components/affiliations/AffiliationsModal.js +3 -3
- package/dist/cjs/components/authors/AuthorsModal.js +3 -3
- package/dist/cjs/components/views/FigureDropdown.js +8 -47
- package/dist/cjs/configs/editor-plugins.js +2 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/lib/context-menu.js +71 -4
- package/dist/cjs/plugins/inspector-tabs.js +84 -0
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/ReactSubView.js +4 -4
- package/dist/cjs/views/affiliations.js +1 -1
- package/dist/cjs/views/award.js +3 -3
- package/dist/cjs/views/bibliography_element.js +2 -2
- package/dist/cjs/views/citation_editable.js +3 -3
- package/dist/cjs/views/contributors.js +2 -2
- package/dist/cjs/views/cross_reference_editable.js +1 -1
- package/dist/cjs/views/embed.js +1 -1
- package/dist/cjs/views/figure_editable.js +91 -7
- package/dist/cjs/views/figure_element.js +0 -79
- package/dist/cjs/views/inline_footnote.js +2 -2
- package/dist/cjs/views/keyword.js +1 -1
- package/dist/cjs/views/keyword_group.js +1 -1
- package/dist/cjs/views/link_editable.js +1 -1
- package/dist/cjs/views/table_cell.js +1 -1
- package/dist/es/components/affiliations/AffiliationItem.js +2 -2
- package/dist/es/components/affiliations/AffiliationsModal.js +3 -3
- package/dist/es/components/authors/AuthorsModal.js +3 -3
- package/dist/es/components/views/FigureDropdown.js +8 -46
- package/dist/es/configs/editor-plugins.js +2 -0
- package/dist/es/index.js +1 -0
- package/dist/es/lib/context-menu.js +72 -5
- package/dist/es/plugins/inspector-tabs.js +81 -0
- package/dist/es/versions.js +1 -1
- package/dist/es/views/ReactSubView.js +4 -4
- package/dist/es/views/affiliations.js +1 -1
- package/dist/es/views/award.js +3 -3
- package/dist/es/views/bibliography_element.js +2 -2
- package/dist/es/views/citation_editable.js +3 -3
- package/dist/es/views/contributors.js +2 -2
- package/dist/es/views/cross_reference_editable.js +1 -1
- package/dist/es/views/embed.js +1 -1
- package/dist/es/views/figure_editable.js +91 -7
- package/dist/es/views/figure_element.js +0 -79
- package/dist/es/views/inline_footnote.js +2 -2
- package/dist/es/views/keyword.js +1 -1
- package/dist/es/views/keyword_group.js +1 -1
- package/dist/es/views/link_editable.js +1 -1
- package/dist/es/views/table_cell.js +1 -1
- package/dist/types/components/views/FigureDropdown.d.ts +0 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/lib/context-menu.d.ts +3 -0
- package/dist/types/plugins/inspector-tabs.d.ts +35 -0
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/ReactSubView.d.ts +1 -1
- package/dist/types/views/figure_editable.d.ts +9 -0
- package/dist/types/views/figure_element.d.ts +0 -3
- package/package.json +3 -3
- package/styles/AdvancedEditor.css +15 -5
- package/styles/Editor.css +10 -1
- package/styles/popper.css +33 -11
|
@@ -27,16 +27,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
28
|
};
|
|
29
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
-
exports.FigureEditableView = void 0;
|
|
30
|
+
exports.FigureEditableView = exports.figurePositions = void 0;
|
|
31
31
|
const style_guide_1 = require("@manuscripts/style-guide");
|
|
32
|
+
const transform_1 = require("@manuscripts/transform");
|
|
32
33
|
const react_1 = require("react");
|
|
33
34
|
const server_1 = require("react-dom/server");
|
|
34
35
|
const FigureDropdown_1 = require("../components/views/FigureDropdown");
|
|
35
36
|
const files_1 = require("../lib/files");
|
|
37
|
+
const view_1 = require("../lib/view");
|
|
36
38
|
const creators_1 = require("./creators");
|
|
37
39
|
const figure_1 = require("./figure");
|
|
38
40
|
const figure_uploader_1 = require("./figure_uploader");
|
|
39
41
|
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
42
|
+
var figurePositions;
|
|
43
|
+
(function (figurePositions) {
|
|
44
|
+
figurePositions["left"] = "half-left";
|
|
45
|
+
figurePositions["right"] = "half-right";
|
|
46
|
+
figurePositions["default"] = "";
|
|
47
|
+
})(figurePositions = exports.figurePositions || (exports.figurePositions = {}));
|
|
40
48
|
class FigureEditableView extends figure_1.FigureView {
|
|
41
49
|
constructor() {
|
|
42
50
|
super(...arguments);
|
|
@@ -84,11 +92,75 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
84
92
|
element.classList.add('figure', 'placeholder');
|
|
85
93
|
const instructions = document.createElement('div');
|
|
86
94
|
instructions.classList.add('instructions');
|
|
87
|
-
instructions.
|
|
88
|
-
|
|
95
|
+
instructions.innerHTML = `
|
|
96
|
+
<p>Drag or click here to upload image <br>
|
|
97
|
+
or drag items here from the file inspector tabs <br>
|
|
98
|
+
<a data-action='open-other-files'>'Other files'</a> |
|
|
99
|
+
<a data-action='open-supplement-files'>'Supplements'</a></p>
|
|
100
|
+
`;
|
|
89
101
|
element.appendChild(instructions);
|
|
90
102
|
return element;
|
|
91
103
|
};
|
|
104
|
+
this.createPositionMenuWrapper = () => {
|
|
105
|
+
this.positionMenuWrapper = document.createElement('div');
|
|
106
|
+
this.positionMenuWrapper.classList.add('position-menu');
|
|
107
|
+
const positionMenuButton = document.createElement('div');
|
|
108
|
+
positionMenuButton.classList.add('position-menu-button');
|
|
109
|
+
let icon;
|
|
110
|
+
switch (this.figurePosition) {
|
|
111
|
+
case figurePositions.left:
|
|
112
|
+
icon = style_guide_1.ImageLeftIcon;
|
|
113
|
+
break;
|
|
114
|
+
case figurePositions.right:
|
|
115
|
+
icon = style_guide_1.ImageRightIcon;
|
|
116
|
+
break;
|
|
117
|
+
default:
|
|
118
|
+
icon = style_guide_1.ImageDefaultIcon;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (icon) {
|
|
122
|
+
positionMenuButton.innerHTML = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(icon));
|
|
123
|
+
}
|
|
124
|
+
positionMenuButton.addEventListener('click', this.showPositionMenu);
|
|
125
|
+
this.positionMenuWrapper.appendChild(positionMenuButton);
|
|
126
|
+
return this.positionMenuWrapper;
|
|
127
|
+
};
|
|
128
|
+
this.showPositionMenu = () => {
|
|
129
|
+
this.props.popper.destroy();
|
|
130
|
+
const figure = this.node;
|
|
131
|
+
const componentProps = {
|
|
132
|
+
actions: [
|
|
133
|
+
{
|
|
134
|
+
label: 'Left',
|
|
135
|
+
action: () => {
|
|
136
|
+
this.props.popper.destroy();
|
|
137
|
+
(0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.figure, Object.assign(Object.assign({}, figure.attrs), { type: figurePositions.left }));
|
|
138
|
+
},
|
|
139
|
+
icon: 'ImageLeft',
|
|
140
|
+
selected: this.figurePosition === figurePositions.left,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
label: 'Default',
|
|
144
|
+
action: () => {
|
|
145
|
+
this.props.popper.destroy();
|
|
146
|
+
(0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.figure, Object.assign(Object.assign({}, figure.attrs), { type: figurePositions.default }));
|
|
147
|
+
},
|
|
148
|
+
icon: 'ImageDefault',
|
|
149
|
+
selected: !this.figurePosition,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
label: 'Right',
|
|
153
|
+
action: () => {
|
|
154
|
+
this.props.popper.destroy();
|
|
155
|
+
(0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.figure, Object.assign(Object.assign({}, figure.attrs), { type: figurePositions.right }));
|
|
156
|
+
},
|
|
157
|
+
icon: 'ImageRight',
|
|
158
|
+
selected: this.figurePosition === figurePositions.right,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
this.props.popper.show(this.positionMenuWrapper, (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu', 'position-menu']), 'left', false);
|
|
163
|
+
};
|
|
92
164
|
}
|
|
93
165
|
updateContents() {
|
|
94
166
|
var _a;
|
|
@@ -97,6 +169,7 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
97
169
|
const src = attrs.src;
|
|
98
170
|
const files = this.props.getFiles();
|
|
99
171
|
const file = src && files.filter((f) => f.id === src)[0];
|
|
172
|
+
this.figurePosition = attrs.type;
|
|
100
173
|
this.container.innerHTML = '';
|
|
101
174
|
const can = this.props.getCapabilities();
|
|
102
175
|
const link = file && this.props.fileManagement.previewLink(file);
|
|
@@ -115,20 +188,30 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
115
188
|
this.props.fileManagement.download(file);
|
|
116
189
|
};
|
|
117
190
|
}
|
|
118
|
-
handleReplace = (file) => {
|
|
119
|
-
this.setSrc(file.id);
|
|
120
|
-
};
|
|
121
191
|
handleDetach = () => {
|
|
122
192
|
this.setSrc('');
|
|
123
193
|
};
|
|
124
194
|
}
|
|
195
|
+
if (can.replaceFile) {
|
|
196
|
+
handleReplace = (file) => {
|
|
197
|
+
this.setSrc(file.id);
|
|
198
|
+
};
|
|
199
|
+
}
|
|
125
200
|
if (can.uploadFile) {
|
|
126
201
|
const upload = (file) => __awaiter(this, void 0, void 0, function* () {
|
|
127
202
|
const result = yield this.props.fileManagement.upload(file);
|
|
128
203
|
this.setSrc(result.id);
|
|
129
204
|
});
|
|
130
205
|
handleUpload = (0, figure_uploader_1.figureUploader)(upload);
|
|
131
|
-
|
|
206
|
+
const handlePlaceholderClick = (event) => {
|
|
207
|
+
const target = event.target;
|
|
208
|
+
if (target.dataset && target.dataset.action) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const triggerUpload = (0, figure_uploader_1.figureUploader)(upload);
|
|
212
|
+
triggerUpload();
|
|
213
|
+
};
|
|
214
|
+
img.addEventListener('click', handlePlaceholderClick);
|
|
132
215
|
img.addEventListener('mouseenter', () => {
|
|
133
216
|
img.classList.toggle('over', true);
|
|
134
217
|
});
|
|
@@ -176,6 +259,7 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
176
259
|
this.reactTools = (0, ReactSubView_1.default)(this.props, FigureDropdown_1.FigureOptions, componentProps, this.node, this.getPos, this.view);
|
|
177
260
|
this.dom.insertBefore(this.reactTools, this.dom.firstChild);
|
|
178
261
|
}
|
|
262
|
+
this.container.appendChild(this.createPositionMenuWrapper());
|
|
179
263
|
}
|
|
180
264
|
}
|
|
181
265
|
exports.FigureEditableView = FigureEditableView;
|
|
@@ -14,28 +14,13 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
18
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
19
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
20
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
21
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
22
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
23
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
17
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
27
18
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
19
|
};
|
|
29
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
21
|
exports.FigureElementView = void 0;
|
|
31
|
-
const transform_1 = require("@manuscripts/transform");
|
|
32
|
-
const FigureDropdown_1 = require("../components/views/FigureDropdown");
|
|
33
|
-
const files_1 = require("../lib/files");
|
|
34
|
-
const utils_1 = require("../lib/utils");
|
|
35
22
|
const block_view_1 = __importDefault(require("./block_view"));
|
|
36
23
|
const creators_1 = require("./creators");
|
|
37
|
-
const figure_uploader_1 = require("./figure_uploader");
|
|
38
|
-
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
39
24
|
class FigureElementView extends block_view_1.default {
|
|
40
25
|
constructor() {
|
|
41
26
|
super(...arguments);
|
|
@@ -50,70 +35,6 @@ class FigureElementView extends block_view_1.default {
|
|
|
50
35
|
this.container.appendChild(this.contentDOM);
|
|
51
36
|
};
|
|
52
37
|
}
|
|
53
|
-
updateContents() {
|
|
54
|
-
var _a;
|
|
55
|
-
super.updateContents();
|
|
56
|
-
if (!this.contentDOM) {
|
|
57
|
-
throw new Error('No contentDOM');
|
|
58
|
-
}
|
|
59
|
-
const can = this.props.getCapabilities();
|
|
60
|
-
let handleUpload = () => {
|
|
61
|
-
};
|
|
62
|
-
const hasUploadedImage = !!(0, utils_1.getMatchingChild)(this.node, (node) => node.type === transform_1.schema.nodes.figure && node.attrs.src);
|
|
63
|
-
const handleAdd = (file) => __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const { state: { tr, schema, selection }, dispatch, } = this.view;
|
|
65
|
-
const src = file.id;
|
|
66
|
-
const figure = (0, utils_1.getMatchingChild)(this.node, (node) => node.type === schema.nodes.figure);
|
|
67
|
-
if (figure === null || figure === void 0 ? void 0 : figure.attrs.src) {
|
|
68
|
-
const figure = schema.nodes.figure.createAndFill({
|
|
69
|
-
src,
|
|
70
|
-
}, []);
|
|
71
|
-
let position = 0;
|
|
72
|
-
this.node.forEach((node, pos) => {
|
|
73
|
-
if (node.type === schema.nodes.figure) {
|
|
74
|
-
position = pos + node.nodeSize;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
dispatch(tr.insert(this.getPos() + position + 1, figure));
|
|
78
|
-
}
|
|
79
|
-
else if (figure) {
|
|
80
|
-
tr.setNodeMarkup(this.getPos() + 1, undefined, Object.assign(Object.assign({}, figure.attrs), { src })).setSelection(selection.map(tr.doc, tr.mapping));
|
|
81
|
-
dispatch(tr);
|
|
82
|
-
}
|
|
83
|
-
this.deleteSupplementNode(file);
|
|
84
|
-
});
|
|
85
|
-
if (can.uploadFile) {
|
|
86
|
-
const upload = (file) => __awaiter(this, void 0, void 0, function* () {
|
|
87
|
-
const result = yield this.props.fileManagement.upload(file);
|
|
88
|
-
yield handleAdd(result);
|
|
89
|
-
});
|
|
90
|
-
handleUpload = (0, figure_uploader_1.figureUploader)(upload);
|
|
91
|
-
}
|
|
92
|
-
if (this.props.dispatch && this.props.theme) {
|
|
93
|
-
const files = this.props.getFiles();
|
|
94
|
-
const doc = this.view.state.doc;
|
|
95
|
-
const componentProps = {
|
|
96
|
-
can: can,
|
|
97
|
-
files: (0, files_1.groupFiles)(doc, files),
|
|
98
|
-
onUpload: handleUpload,
|
|
99
|
-
onAdd: handleAdd,
|
|
100
|
-
hasUploadedImage: hasUploadedImage,
|
|
101
|
-
};
|
|
102
|
-
(_a = this.reactTools) === null || _a === void 0 ? void 0 : _a.remove();
|
|
103
|
-
this.reactTools = (0, ReactSubView_1.default)(this.props, FigureDropdown_1.FigureElementOptions, componentProps, this.node, this.getPos, this.view);
|
|
104
|
-
this.dom.insertBefore(this.reactTools, this.dom.firstChild);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
deleteSupplementNode(file) {
|
|
108
|
-
const tr = this.view.state.tr;
|
|
109
|
-
this.view.state.doc.descendants((node, pos) => {
|
|
110
|
-
if (node.type === transform_1.schema.nodes.supplement &&
|
|
111
|
-
node.attrs.href === file.id) {
|
|
112
|
-
tr.delete(pos, pos + node.nodeSize);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
this.view.dispatch(tr);
|
|
116
|
-
}
|
|
117
38
|
}
|
|
118
39
|
exports.FigureElementView = FigureElementView;
|
|
119
40
|
exports.default = (0, creators_1.createNodeView)(FigureElementView);
|
|
@@ -58,7 +58,7 @@ class InlineFootnoteView extends base_node_view_1.BaseNodeView {
|
|
|
58
58
|
},
|
|
59
59
|
],
|
|
60
60
|
};
|
|
61
|
-
this.props.popper.show(this.dom, (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu'), 'right-start', false);
|
|
61
|
+
this.props.popper.show(this.dom, (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu']), 'right-start', false);
|
|
62
62
|
};
|
|
63
63
|
this.handleClick = () => {
|
|
64
64
|
if ((0, track_changes_utils_1.isDeleted)(this.node)) {
|
|
@@ -106,7 +106,7 @@ class InlineFootnoteView extends base_node_view_1.BaseNodeView {
|
|
|
106
106
|
onAdd: this.handleAdd,
|
|
107
107
|
onInsert: this.handleInsert,
|
|
108
108
|
};
|
|
109
|
-
this.popperContainer = (0, ReactSubView_1.default)(this.props, FootnotesSelector_1.FootnotesSelector, props, this.node, this.getPos, this.view, 'footnote-editor');
|
|
109
|
+
this.popperContainer = (0, ReactSubView_1.default)(this.props, FootnotesSelector_1.FootnotesSelector, props, this.node, this.getPos, this.view, ['footnote-editor']);
|
|
110
110
|
this.props.popper.show(this.dom, this.popperContainer, 'auto', false);
|
|
111
111
|
};
|
|
112
112
|
this.initialise = () => {
|
|
@@ -58,7 +58,7 @@ class KeywordView extends base_node_view_1.BaseNodeView {
|
|
|
58
58
|
keyword: keyword.textContent,
|
|
59
59
|
handleDelete: handleDelete,
|
|
60
60
|
};
|
|
61
|
-
this.dialog = (0, ReactSubView_1.default)(this.props, DeleteKeywordDialog_1.DeleteKeywordDialog, componentProps, this.node, this.getPos, this.view, 'keywords-delete');
|
|
61
|
+
this.dialog = (0, ReactSubView_1.default)(this.props, DeleteKeywordDialog_1.DeleteKeywordDialog, componentProps, this.node, this.getPos, this.view, ['keywords-delete']);
|
|
62
62
|
if (this.dialog) {
|
|
63
63
|
this.dom.appendChild(this.dialog);
|
|
64
64
|
}
|
|
@@ -37,7 +37,7 @@ class KeywordGroupView extends block_view_1.default {
|
|
|
37
37
|
this.contentDOM.setAttribute('contenteditable', 'false');
|
|
38
38
|
this.element.appendChild(this.contentDOM);
|
|
39
39
|
if (this.props.getCapabilities().editArticle) {
|
|
40
|
-
this.addingTools = (0, ReactSubView_1.default)(this.props, AddKeywordInline_1.AddKeywordInline, { getUpdatedNode: () => this.node }, this.node, this.getPos, this.view, 'keywords-editor');
|
|
40
|
+
this.addingTools = (0, ReactSubView_1.default)(this.props, AddKeywordInline_1.AddKeywordInline, { getUpdatedNode: () => this.node }, this.node, this.getPos, this.view, ['keywords-editor']);
|
|
41
41
|
}
|
|
42
42
|
if (this.addingTools) {
|
|
43
43
|
this.element.appendChild(this.addingTools);
|
|
@@ -71,7 +71,7 @@ class LinkEditableView extends link_1.LinkView {
|
|
|
71
71
|
onRemove: this.handleRemove,
|
|
72
72
|
onSave: this.handleSave,
|
|
73
73
|
};
|
|
74
|
-
this.popperContainer = (0, ReactSubView_1.default)(this.props, LinkForm_1.LinkForm, componentProps, this.node, this.getPos, this.view, 'link-editor');
|
|
74
|
+
this.popperContainer = (0, ReactSubView_1.default)(this.props, LinkForm_1.LinkForm, componentProps, this.node, this.getPos, this.view, ['link-editor']);
|
|
75
75
|
this.props.popper.show(this.dom, this.popperContainer, 'bottom');
|
|
76
76
|
};
|
|
77
77
|
this.handleClick = (e) => {
|
|
@@ -79,7 +79,7 @@ class TableCellView extends block_view_1.default {
|
|
|
79
79
|
contextMenuButton.classList.toggle('open-context-menu');
|
|
80
80
|
},
|
|
81
81
|
onCancelColumnDialog: () => this.addOutClickListener(contextMenuButton),
|
|
82
|
-
}, this.view.state.selection.$from.node(), this.getPos, this.view, 'table-cell-context-menu');
|
|
82
|
+
}, this.view.state.selection.$from.node(), this.getPos, this.view, ['table-cell-context-menu']);
|
|
83
83
|
contextMenuButton.classList.toggle('open-context-menu');
|
|
84
84
|
this.props.popper.show(contextMenuButton, contextMenu, 'right', false);
|
|
85
85
|
this.addOutClickListener(contextMenuButton);
|
|
@@ -63,10 +63,10 @@ export const AffiliationItem = ({ affiliation, isSelected, onClick, onDelete, sh
|
|
|
63
63
|
block: 'nearest',
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
|
-
return (React.createElement(AffiliationContainer, { onClick: onClick, className: isSelected ? 'active' : '', ref: ref },
|
|
66
|
+
return (React.createElement(AffiliationContainer, { "data-cy": "affiliation-item", onClick: onClick, className: isSelected ? 'active' : '', ref: ref },
|
|
67
67
|
React.createElement(AffiliationIcon, { opacity: showSuccessIcon ? 0.05 : 1, style: { minWidth: 24, minHeight: 24 } }),
|
|
68
68
|
React.createElement(AffiliationBox, null,
|
|
69
|
-
React.createElement(AffiliationName,
|
|
69
|
+
React.createElement(AffiliationName, { "data-cy": "affiliation-name" }, affiliation.institution),
|
|
70
70
|
React.createElement(AffiliationDetails, null,
|
|
71
71
|
affiliation.city && (React.createElement(React.Fragment, null,
|
|
72
72
|
affiliation.city,
|
|
@@ -355,7 +355,7 @@ export const AffiliationsModal = ({ authors: $authors, affiliations: $affiliatio
|
|
|
355
355
|
}
|
|
356
356
|
};
|
|
357
357
|
return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: true },
|
|
358
|
-
React.createElement(ModalContainer,
|
|
358
|
+
React.createElement(ModalContainer, { "data-cy": "affiliations-modal" },
|
|
359
359
|
React.createElement(ModalHeader, null,
|
|
360
360
|
React.createElement(CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
|
|
361
361
|
React.createElement(StyledModalBody, null,
|
|
@@ -378,9 +378,9 @@ export const AffiliationsModal = ({ authors: $authors, affiliations: $affiliatio
|
|
|
378
378
|
React.createElement(AffiliateButton, { onClick: () => setShowAuthorDrawer(true), "data-cy": "affiliate-authors-button" },
|
|
379
379
|
React.createElement(AddUserIcon, { width: 16, height: 16 }),
|
|
380
380
|
"Affiliate Authors")),
|
|
381
|
-
React.createElement(SelectedItemsBox, { items: selectedAuthors, onRemove: (id) => {
|
|
381
|
+
React.createElement(SelectedItemsBox, { "data-cy": "affiliation-authors", items: selectedAuthors, onRemove: (id) => {
|
|
382
382
|
setSelectedIds((prev) => prev.filter((authorId) => authorId !== id));
|
|
383
383
|
}, placeholder: "No authors assigned" })),
|
|
384
|
-
showAuthorDrawer && (React.createElement(Drawer, { items: authorItems, selectedIds: selectedIds, title: "Authors", onSelect: handleAuthorSelect, onBack: () => setShowAuthorDrawer(false), width: "100%" })))) : (React.createElement(FormPlaceholder, { type: "affiliation", title:
|
|
384
|
+
showAuthorDrawer && (React.createElement(Drawer, { items: authorItems, selectedIds: selectedIds, title: "Authors", onSelect: handleAuthorSelect, onBack: () => setShowAuthorDrawer(false), width: "100%" })))) : (React.createElement(FormPlaceholder, { type: "affiliation", title: "Affiliation Details", message: "Select an affiliation from the list to display it's details here.", placeholderIcon: React.createElement(AffiliationPlaceholderIcon, null) })))),
|
|
385
385
|
React.createElement(FormFooter, { onCancel: handleClose }))));
|
|
386
386
|
};
|
|
@@ -432,7 +432,7 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
432
432
|
setSelectedAffiliations(affiliationItems.filter((item) => newAffiliations.includes(item.id)));
|
|
433
433
|
};
|
|
434
434
|
return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: true },
|
|
435
|
-
React.createElement(ModalContainer,
|
|
435
|
+
React.createElement(ModalContainer, { "data-cy": "authors-modal" },
|
|
436
436
|
React.createElement(ModalHeader, null,
|
|
437
437
|
React.createElement(CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
|
|
438
438
|
React.createElement(StyledModalBody, null,
|
|
@@ -459,7 +459,7 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
459
459
|
React.createElement(AffiliateButton, { onClick: () => setShowAffiliationDrawer(true), "data-cy": "affiliate-authors-button" },
|
|
460
460
|
React.createElement(AddInstitutionIcon, { width: 16, height: 16 }),
|
|
461
461
|
"Assign Institutions")),
|
|
462
|
-
React.createElement(SelectedItemsBox, { items: selectedAffiliations, onRemove: handleRemoveAffiliation, placeholder: "No institutions assigned" })),
|
|
463
|
-
showAffiliationDrawer && (React.createElement(Drawer, { items: affiliationItems, selectedIds: selectedAffiliationIds, title: "Authors", onSelect: handleAffiliationSelect, onBack: () => setShowAffiliationDrawer(false), width: "100%" })))) : (React.createElement(FormPlaceholder, { type: "author", title:
|
|
462
|
+
React.createElement(SelectedItemsBox, { "data-cy": "author-affiliations", items: selectedAffiliations, onRemove: handleRemoveAffiliation, placeholder: "No institutions assigned" })),
|
|
463
|
+
showAffiliationDrawer && (React.createElement(Drawer, { items: affiliationItems, selectedIds: selectedAffiliationIds, title: "Authors", onSelect: handleAffiliationSelect, onBack: () => setShowAffiliationDrawer(false), width: "100%" })))) : (React.createElement(FormPlaceholder, { type: "author", title: "Author Details", message: "Select an author from the list to display their details here.", placeholderIcon: React.createElement(AuthorPlaceholderIcon, null) })))),
|
|
464
464
|
React.createElement(FormFooter, { onCancel: handleClose }))));
|
|
465
465
|
};
|
|
@@ -1,26 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DotsIcon, DropdownList, getFileIcon, IconButton, IconTextButton, isImageFile, TriangleCollapsedIcon, UploadIcon, useDropdown, } from '@manuscripts/style-guide';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
|
-
export const FigureElementOptions = ({ can, files, onAdd, onUpload, hasUploadedImage, }) => {
|
|
5
|
-
const { isOpen, toggleOpen, wrapperRef } = useDropdown();
|
|
6
|
-
const supplements = files.supplements
|
|
7
|
-
.map((s) => s.file)
|
|
8
|
-
.filter((f) => isImageFile(f.name));
|
|
9
|
-
const others = files.others.filter((f) => isImageFile(f.name));
|
|
10
|
-
return (React.createElement(FilesDropdownWrapper, { onClick: toggleOpen, ref: wrapperRef },
|
|
11
|
-
React.createElement(FilesButton, { disabled: hasUploadedImage },
|
|
12
|
-
React.createElement(AttachIcon, null)),
|
|
13
|
-
isOpen && (React.createElement(DropdownList, { direction: 'left', width: 208, height: 187, onClick: toggleOpen, top: 7 },
|
|
14
|
-
React.createElement(NestedDropdown, { disabled: !can.replaceFile || supplements.length < 1, parentToggleOpen: toggleOpen, buttonText: 'Supplements', list: React.createElement(React.Fragment, null, supplements.map((file) => (React.createElement(ListItemButton, { key: file.id, onClick: () => onAdd(file) },
|
|
15
|
-
getFileIcon(file.name),
|
|
16
|
-
React.createElement(ListItemText, null, file.name))))) }),
|
|
17
|
-
React.createElement(NestedDropdown, { disabled: !can.replaceFile || others.length < 1, parentToggleOpen: toggleOpen, buttonText: 'Other files', list: React.createElement(React.Fragment, null, others.map((file) => (React.createElement(ListItemButton, { key: file.id, onClick: () => onAdd(file) },
|
|
18
|
-
getFileIcon(file.name),
|
|
19
|
-
React.createElement(ListItemText, null, file.name))))) }),
|
|
20
|
-
React.createElement(UploadButton, { onClick: onUpload, disabled: !can.uploadFile },
|
|
21
|
-
React.createElement(AddIcon, null),
|
|
22
|
-
" New file...")))));
|
|
23
|
-
};
|
|
24
4
|
export const FigureOptions = ({ can, files, onDownload, onUpload, onDetach, onReplace, }) => {
|
|
25
5
|
const { isOpen, toggleOpen, wrapperRef } = useDropdown();
|
|
26
6
|
const otherFiles = files.others.filter((f) => isImageFile(f.name));
|
|
@@ -28,26 +8,26 @@ export const FigureOptions = ({ can, files, onDownload, onUpload, onDetach, onRe
|
|
|
28
8
|
const showUpload = onUpload && can.uploadFile;
|
|
29
9
|
const showDetach = onDetach && can.detachFile;
|
|
30
10
|
const showReplace = onReplace && can.replaceFile;
|
|
11
|
+
const replaceBtnText = onDownload ? 'Replace' : 'Choose file';
|
|
31
12
|
return (React.createElement(DropdownWrapper, { ref: wrapperRef },
|
|
32
13
|
React.createElement(OptionsButton, { className: 'options-button', onClick: toggleOpen },
|
|
33
14
|
React.createElement(DotsIcon, null)),
|
|
34
15
|
isOpen && (React.createElement(OptionsDropdownList, { direction: 'right', width: 128, top: 5 },
|
|
35
|
-
React.createElement(
|
|
36
|
-
React.createElement(NestedDropdown, { disabled: !showReplace, parentToggleOpen: toggleOpen, buttonText: 'Replace', moveLeft: true, list: React.createElement(React.Fragment, null,
|
|
16
|
+
React.createElement(NestedDropdown, { disabled: !showReplace, parentToggleOpen: toggleOpen, buttonText: replaceBtnText, moveLeft: true, list: React.createElement(React.Fragment, null,
|
|
37
17
|
otherFiles.map((file, index) => (React.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
|
|
38
18
|
getFileIcon(file.name),
|
|
39
19
|
React.createElement(ListItemText, null, file.name)))),
|
|
40
20
|
React.createElement(UploadButton, { onClick: onUpload, disabled: !showUpload },
|
|
41
21
|
React.createElement(UploadIcon, null),
|
|
42
22
|
" Upload new...")) }),
|
|
23
|
+
React.createElement(ListItemButton, { onClick: onDownload, disabled: !showDownload }, "Download"),
|
|
43
24
|
React.createElement(ListItemButton, { onClick: onDetach, disabled: !showDetach }, "Detach")))));
|
|
44
25
|
};
|
|
45
26
|
const NestedDropdown = ({ parentToggleOpen, buttonText, disabled, list, moveLeft }) => {
|
|
46
27
|
const { isOpen, toggleOpen, wrapperRef } = useDropdown();
|
|
47
28
|
return (React.createElement(DropdownWrapper, { ref: wrapperRef },
|
|
48
29
|
React.createElement(NestedListButton, { onClick: toggleOpen, disabled: disabled },
|
|
49
|
-
buttonText,
|
|
50
|
-
" ",
|
|
30
|
+
React.createElement("div", null, buttonText),
|
|
51
31
|
React.createElement(TriangleCollapsedIcon, null)),
|
|
52
32
|
isOpen && (React.createElement(NestedListDropdownList, { direction: 'right', moveLeft: moveLeft, width: 192, onClick: (e) => {
|
|
53
33
|
toggleOpen();
|
|
@@ -67,9 +47,6 @@ const OptionsButton = styled(IconButton) `
|
|
|
67
47
|
margin: ${(props) => props.theme.grid.unit}px;
|
|
68
48
|
visibility: hidden;
|
|
69
49
|
background: white;
|
|
70
|
-
position: absolute;
|
|
71
|
-
top: -4px;
|
|
72
|
-
right: 4%;
|
|
73
50
|
|
|
74
51
|
&:hover {
|
|
75
52
|
background: #f2fbfc !important;
|
|
@@ -111,30 +88,15 @@ const ListItemText = styled.div `
|
|
|
111
88
|
text-overflow: ellipsis;
|
|
112
89
|
text-align: start;
|
|
113
90
|
`;
|
|
114
|
-
const FilesButton = styled(RoundIconButton) `
|
|
115
|
-
path {
|
|
116
|
-
stroke: #6e6e6e;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
&:active,
|
|
120
|
-
&:focus {
|
|
121
|
-
path {
|
|
122
|
-
stroke: #1a9bc7;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
`;
|
|
126
|
-
const FilesDropdownWrapper = styled.div `
|
|
127
|
-
position: absolute;
|
|
128
|
-
top: 8px;
|
|
129
|
-
left: 70px;
|
|
130
|
-
z-index: 1;
|
|
131
|
-
`;
|
|
132
91
|
const NestedListButton = styled(ListItemButton) `
|
|
133
92
|
width: 100%;
|
|
134
93
|
&:active,
|
|
135
94
|
&:focus {
|
|
136
95
|
background: #f2fbfc;
|
|
137
96
|
}
|
|
97
|
+
svg {
|
|
98
|
+
margin-right: 0;
|
|
99
|
+
}
|
|
138
100
|
`;
|
|
139
101
|
const NestedListDropdownList = styled(DropdownList) `
|
|
140
102
|
top: 0;
|
|
@@ -29,6 +29,7 @@ import doi from '../plugins/doi';
|
|
|
29
29
|
import editorProps from '../plugins/editor-props';
|
|
30
30
|
import elements from '../plugins/elements';
|
|
31
31
|
import footnotes from '../plugins/footnotes';
|
|
32
|
+
import inspector_tabs from '../plugins/inspector-tabs';
|
|
32
33
|
import objects from '../plugins/objects';
|
|
33
34
|
import paragraphs from '../plugins/paragraphs';
|
|
34
35
|
import persist from '../plugins/persist';
|
|
@@ -70,6 +71,7 @@ export default (props) => {
|
|
|
70
71
|
doi(),
|
|
71
72
|
section_category(props),
|
|
72
73
|
cross_references(),
|
|
74
|
+
inspector_tabs(),
|
|
73
75
|
];
|
|
74
76
|
if (props.collabProvider) {
|
|
75
77
|
allPlugins.push(collab({ version: props.collabProvider.currentVersion }));
|
package/dist/es/index.js
CHANGED
|
@@ -39,3 +39,4 @@ export { footnotesKey as footnotesPluginKey } from './plugins/footnotes';
|
|
|
39
39
|
export { bibliographyKey as bibliographyPluginKey } from './plugins/bibliography';
|
|
40
40
|
export { metadata } from './lib/references';
|
|
41
41
|
export { authorLabel, affiliationLabel, } from './lib/authors';
|
|
42
|
+
export * from './plugins/inspector-tabs';
|
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { ImageDefaultIcon, ImageLeftIcon, ImageRightIcon, TriangleCollapsedIcon, } from '@manuscripts/style-guide';
|
|
16
17
|
import { getListType, isInBibliographySection, isSectionTitleNode, nodeNames, schema, } from '@manuscripts/transform';
|
|
17
18
|
import { findChildrenByType } from 'prosemirror-utils';
|
|
19
|
+
import { createElement } from 'react';
|
|
20
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
18
21
|
import { addNodeComment, createBlock, findPosBeforeFirstSubsection, insertGeneralTableFootnote, insertInlineTableFootnote, } from '../commands';
|
|
22
|
+
import { figurePositions } from '../views/figure_editable';
|
|
19
23
|
import { PopperManager } from './popper';
|
|
20
|
-
import { isChildOfNodeTypes, isSelectionInNode } from './utils';
|
|
24
|
+
import { getMatchingChild, isChildOfNodeTypes, isSelectionInNode, } from './utils';
|
|
25
|
+
import { updateNodeAttrs } from './view';
|
|
21
26
|
const popper = new PopperManager();
|
|
22
27
|
const readonlyTypes = [
|
|
23
28
|
schema.nodes.keywords,
|
|
@@ -38,6 +43,7 @@ const hasAny = (set, ...items) => {
|
|
|
38
43
|
return items.some((i) => set.has(i));
|
|
39
44
|
};
|
|
40
45
|
export const contextMenuBtnClass = 'btn-context-menu';
|
|
46
|
+
const contextSubmenuBtnClass = 'context-submenu-trigger';
|
|
41
47
|
export class ContextMenu {
|
|
42
48
|
constructor(node, view, getPos, actions = {}) {
|
|
43
49
|
this.showAddMenu = (target, after) => {
|
|
@@ -146,6 +152,36 @@ export class ContextMenu {
|
|
|
146
152
|
const $pos = this.resolvePos();
|
|
147
153
|
const isBox = isBoxElementSectionTitle($pos, this.node);
|
|
148
154
|
const type = isBox ? schema.nodes.box_element : this.node.type;
|
|
155
|
+
if (type === schema.nodes.figure_element ||
|
|
156
|
+
type === schema.nodes.image_element) {
|
|
157
|
+
const figure = getMatchingChild(this.node, (node) => node.type === schema.nodes.figure);
|
|
158
|
+
if (figure) {
|
|
159
|
+
const attrType = figure.attrs.type;
|
|
160
|
+
const submenuOptions = [
|
|
161
|
+
{
|
|
162
|
+
title: 'Left',
|
|
163
|
+
action: () => updateNodeAttrs(this.view, schema.nodes.figure, Object.assign(Object.assign({}, figure.attrs), { type: figurePositions.left })),
|
|
164
|
+
Icon: ImageLeftIcon,
|
|
165
|
+
selected: attrType === figurePositions.left,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
title: 'Default',
|
|
169
|
+
action: () => updateNodeAttrs(this.view, schema.nodes.figure, Object.assign(Object.assign({}, figure.attrs), { type: figurePositions.default })),
|
|
170
|
+
Icon: ImageDefaultIcon,
|
|
171
|
+
selected: !attrType,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
title: 'Right',
|
|
175
|
+
action: () => updateNodeAttrs(this.view, schema.nodes.figure, Object.assign(Object.assign({}, figure.attrs), { type: figurePositions.right })),
|
|
176
|
+
Icon: ImageRightIcon,
|
|
177
|
+
selected: attrType === figurePositions.right,
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
const submenuLabel = 'Position';
|
|
181
|
+
const submenu = this.createSubmenu(submenuLabel, submenuOptions);
|
|
182
|
+
menu.appendChild(submenu);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
149
185
|
if (type === schema.nodes.list) {
|
|
150
186
|
menu.appendChild(this.createMenuSection((section) => {
|
|
151
187
|
const attrs = this.node.attrs;
|
|
@@ -210,22 +246,48 @@ export class ContextMenu {
|
|
|
210
246
|
popper.show(target, menu, 'right', true);
|
|
211
247
|
this.addPopperEventListeners();
|
|
212
248
|
};
|
|
213
|
-
this.
|
|
249
|
+
this.createSubmenuTrigger = (contents) => {
|
|
250
|
+
const item = document.createElement('div');
|
|
251
|
+
item.className = 'menu-item';
|
|
252
|
+
const textNode = document.createTextNode(contents);
|
|
253
|
+
item.innerHTML = renderToStaticMarkup(createElement(TriangleCollapsedIcon));
|
|
254
|
+
item.prepend(textNode);
|
|
255
|
+
item.classList.add(contextSubmenuBtnClass);
|
|
256
|
+
item.addEventListener('mousedown', this.toggleSubmenu);
|
|
257
|
+
return item;
|
|
258
|
+
};
|
|
259
|
+
this.createMenuItem = (contents, handler, Icon = null, selected = false) => {
|
|
214
260
|
const item = document.createElement('div');
|
|
215
261
|
item.className = 'menu-item';
|
|
216
|
-
item.
|
|
262
|
+
selected && item.classList.add('selected');
|
|
263
|
+
if (Icon) {
|
|
264
|
+
item.innerHTML = renderToStaticMarkup(createElement(Icon));
|
|
265
|
+
}
|
|
266
|
+
const textNode = document.createTextNode(contents);
|
|
267
|
+
item.appendChild(textNode);
|
|
217
268
|
item.addEventListener('mousedown', (event) => {
|
|
218
269
|
event.preventDefault();
|
|
219
270
|
handler(event);
|
|
220
271
|
});
|
|
221
272
|
return item;
|
|
222
273
|
};
|
|
223
|
-
this.createMenuSection = (createMenuItems) => {
|
|
274
|
+
this.createMenuSection = (createMenuItems, isSubmenu = false) => {
|
|
224
275
|
const section = document.createElement('div');
|
|
225
276
|
section.className = 'menu-section';
|
|
277
|
+
isSubmenu && section.classList.add('menu');
|
|
226
278
|
createMenuItems(section);
|
|
227
279
|
return section;
|
|
228
280
|
};
|
|
281
|
+
this.createSubmenu = (submenuLabel, items) => {
|
|
282
|
+
const submenu = document.createElement('div');
|
|
283
|
+
submenu.classList.add('menu-section', 'context-submenu');
|
|
284
|
+
submenu.append(this.createSubmenuTrigger(submenuLabel), this.createMenuSection((section) => {
|
|
285
|
+
items.forEach(({ title, action, Icon, selected }) => {
|
|
286
|
+
section.appendChild(this.createMenuItem(title, action, Icon, selected));
|
|
287
|
+
});
|
|
288
|
+
}, true));
|
|
289
|
+
return submenu;
|
|
290
|
+
};
|
|
229
291
|
this.insertableTypes = (after, insertPos, endPos) => {
|
|
230
292
|
const { nodes } = schema;
|
|
231
293
|
const insertable = new Set();
|
|
@@ -287,7 +349,8 @@ export class ContextMenu {
|
|
|
287
349
|
this.addPopperEventListeners = () => {
|
|
288
350
|
const mouseListener = (event) => {
|
|
289
351
|
const target = event.target;
|
|
290
|
-
if (target.classList.contains(contextMenuBtnClass)
|
|
352
|
+
if (target.classList.contains(contextMenuBtnClass) ||
|
|
353
|
+
target.classList.contains(contextSubmenuBtnClass)) {
|
|
291
354
|
return;
|
|
292
355
|
}
|
|
293
356
|
window.requestAnimationFrame(() => {
|
|
@@ -319,6 +382,10 @@ export class ContextMenu {
|
|
|
319
382
|
}
|
|
320
383
|
return this.node;
|
|
321
384
|
};
|
|
385
|
+
this.toggleSubmenu = (ev) => {
|
|
386
|
+
const submenu = ev.target.nextElementSibling;
|
|
387
|
+
submenu === null || submenu === void 0 ? void 0 : submenu.classList.toggle('show');
|
|
388
|
+
};
|
|
322
389
|
this.node = node;
|
|
323
390
|
this.view = view;
|
|
324
391
|
this.getPos = getPos;
|