@manuscripts/body-editor 3.2.35 → 3.2.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/commands.js +19 -10
- package/dist/cjs/components/toolbar/InsertEmbedDialog.js +1 -1
- package/dist/cjs/components/views/FigureDropdown.js +30 -13
- package/dist/cjs/configs/editor-views.js +1 -1
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/lib/context-menu.js +12 -36
- package/dist/cjs/lib/get-media-type.js +77 -0
- package/dist/cjs/lib/media.js +207 -0
- package/dist/cjs/lib/position-menu.js +122 -0
- package/dist/cjs/menus.js +1 -2
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/embed.js +188 -64
- package/dist/cjs/views/figure_editable.js +11 -134
- package/dist/cjs/views/image_element.js +36 -57
- package/dist/es/commands.js +17 -8
- package/dist/es/components/toolbar/InsertEmbedDialog.js +1 -1
- package/dist/es/components/views/FigureDropdown.js +31 -14
- package/dist/es/configs/editor-views.js +1 -1
- package/dist/es/index.js +2 -0
- package/dist/es/lib/context-menu.js +13 -37
- package/dist/es/lib/get-media-type.js +73 -0
- package/dist/es/lib/media.js +195 -0
- package/dist/es/lib/position-menu.js +111 -0
- package/dist/es/menus.js +2 -3
- package/dist/es/versions.js +1 -1
- package/dist/es/views/embed.js +187 -63
- package/dist/es/views/figure_editable.js +12 -132
- package/dist/es/views/image_element.js +36 -57
- package/dist/types/commands.d.ts +1 -1
- package/dist/types/components/views/FigureDropdown.d.ts +3 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/lib/files.d.ts +1 -0
- package/dist/types/lib/get-media-type.d.ts +11 -0
- package/dist/types/lib/media.d.ts +33 -0
- package/dist/types/lib/position-menu.d.ts +34 -0
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/embed.d.ts +43 -22
- package/dist/types/views/figure_editable.d.ts +4 -2
- package/dist/types/views/image_element.d.ts +0 -1
- package/package.json +4 -4
- package/styles/AdvancedEditor.css +95 -33
- package/styles/Editor.css +4 -2
package/dist/cjs/commands.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.addRows = exports.addInlineComment = exports.addNodeComment = exports.isCommentingAllowed = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertKeywords = exports.insertAward = exports.insertAffiliation = exports.insertContributors = exports.insertGraphicalAbstract = exports.insertBackmatterSection = exports.insertAbstractSection = exports.insertSection = exports.insertBoxElement = exports.insertInlineFootnote = exports.insertFootnotesElement = exports.insertTableElementFooter = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.findPosBeforeFirstSubsection = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertAttachment = exports.insertSupplement = exports.insertTable = exports.
|
|
18
|
+
exports.addRows = exports.addInlineComment = exports.addNodeComment = exports.isCommentingAllowed = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertKeywords = exports.insertAward = exports.insertAffiliation = exports.insertContributors = exports.insertGraphicalAbstract = exports.insertBackmatterSection = exports.insertAbstractSection = exports.insertSection = exports.insertBoxElement = exports.insertInlineFootnote = exports.insertFootnotesElement = exports.insertTableElementFooter = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.findPosBeforeFirstSubsection = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertAttachment = exports.insertSupplement = exports.insertTable = exports.insertEmbed = exports.insertFigure = exports.insertGeneralTableFootnote = exports.insertInlineTableFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = exports.addToStart = void 0;
|
|
19
19
|
exports.insertHeroImage = exports.activateSearchReplace = exports.activateSearch = exports.autoComplete = exports.addColumns = exports.addHeaderRow = void 0;
|
|
20
20
|
const json_schema_1 = require("@manuscripts/json-schema");
|
|
21
21
|
const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
|
|
@@ -195,15 +195,6 @@ const createBlock = (nodeType, position, state, dispatch, attrs) => {
|
|
|
195
195
|
}
|
|
196
196
|
};
|
|
197
197
|
exports.createBlock = createBlock;
|
|
198
|
-
const insertEmbed = (state, dispatch, attrs) => {
|
|
199
|
-
const position = findBlockInsertPosition(state);
|
|
200
|
-
if (position === null) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
(0, exports.createBlock)(transform_1.schema.nodes.embed, position, state, dispatch, attrs);
|
|
204
|
-
return true;
|
|
205
|
-
};
|
|
206
|
-
exports.insertEmbed = insertEmbed;
|
|
207
198
|
const insertInlineTableFootnote = (state, dispatch) => {
|
|
208
199
|
const $pos = state.selection.$to;
|
|
209
200
|
const table = (0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)($pos, transform_1.schema.nodes.table);
|
|
@@ -257,6 +248,24 @@ const insertFigure = (file, state, dispatch) => {
|
|
|
257
248
|
return true;
|
|
258
249
|
};
|
|
259
250
|
exports.insertFigure = insertFigure;
|
|
251
|
+
const insertEmbed = (state, dispatch, attrs) => {
|
|
252
|
+
const position = findBlockInsertPosition(state);
|
|
253
|
+
if (position === null) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
const embed = transform_1.schema.nodes.embed.create({
|
|
257
|
+
...attrs,
|
|
258
|
+
id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.embed),
|
|
259
|
+
}, [
|
|
260
|
+
createAndFillFigcaptionElement(),
|
|
261
|
+
transform_1.schema.nodes.alt_text.create(),
|
|
262
|
+
transform_1.schema.nodes.long_desc.create(),
|
|
263
|
+
]);
|
|
264
|
+
const tr = state.tr.insert(position, embed);
|
|
265
|
+
dispatch && dispatch(tr);
|
|
266
|
+
return true;
|
|
267
|
+
};
|
|
268
|
+
exports.insertEmbed = insertEmbed;
|
|
260
269
|
const insertTable = (config, state, dispatch) => {
|
|
261
270
|
const pos = findBlockInsertPosition(state);
|
|
262
271
|
if (!pos) {
|
|
@@ -95,7 +95,7 @@ const InsertEmbedDialog = ({ state, dispatch, pos, }) => {
|
|
|
95
95
|
setOEmbedHTML(html);
|
|
96
96
|
});
|
|
97
97
|
}, [url]);
|
|
98
|
-
const operation = pos ? 'Update' : 'Insert';
|
|
98
|
+
const operation = pos !== undefined && attrs?.href ? 'Update' : 'Insert';
|
|
99
99
|
return (react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: () => setOpen(false) },
|
|
100
100
|
react_1.default.createElement(DialogContainer, { "data-cy": "media-editor" },
|
|
101
101
|
react_1.default.createElement(HeaderContainer, null,
|
|
@@ -31,20 +31,35 @@ const style_guide_1 = require("@manuscripts/style-guide");
|
|
|
31
31
|
const react_1 = __importStar(require("react"));
|
|
32
32
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
33
33
|
const files_1 = require("../../lib/files");
|
|
34
|
-
|
|
34
|
+
const get_media_type_1 = require("../../lib/get-media-type");
|
|
35
|
+
function getSupplements(getFiles, getDoc, groupFiles, isEmbed, currentFileHref) {
|
|
35
36
|
return groupFiles(getDoc(), getFiles())
|
|
36
37
|
.supplements.map((s) => s.file)
|
|
37
|
-
.filter((f) =>
|
|
38
|
+
.filter((f) => {
|
|
39
|
+
if (currentFileHref && f.id === currentFileHref) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const mediaInfo = (0, get_media_type_1.getMediaTypeInfo)(f.name);
|
|
43
|
+
return isEmbed
|
|
44
|
+
? mediaInfo.isVideo || mediaInfo.isAudio
|
|
45
|
+
: mediaInfo.isImage;
|
|
46
|
+
});
|
|
38
47
|
}
|
|
39
|
-
function getOtherFiles(getFiles, getDoc, groupFiles) {
|
|
40
|
-
return groupFiles(getDoc(), getFiles()).others.filter((f) =>
|
|
48
|
+
function getOtherFiles(getFiles, getDoc, groupFiles, isEmbed, currentFileHref) {
|
|
49
|
+
return groupFiles(getDoc(), getFiles()).others.filter((f) => {
|
|
50
|
+
if (currentFileHref && f.id === currentFileHref) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const mediaInfo = (0, get_media_type_1.getMediaTypeInfo)(f.name);
|
|
54
|
+
return isEmbed ? mediaInfo.isVideo || mediaInfo.isAudio : mediaInfo.isImage;
|
|
55
|
+
});
|
|
41
56
|
}
|
|
42
|
-
const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onDetach, onReplace, onDelete, hasSiblings, container, }) => {
|
|
57
|
+
const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onDetach, onReplace, onReplaceEmbed, onDelete, isEmbed, hasSiblings, container, currentFileHref, }) => {
|
|
43
58
|
const { isOpen, toggleOpen, wrapperRef } = (0, style_guide_1.useDropdown)();
|
|
44
59
|
const showDownload = onDownload && can.downloadFiles;
|
|
45
60
|
const showUpload = onUpload && can.uploadFile;
|
|
46
61
|
const showDetach = onDetach && can.detachFile;
|
|
47
|
-
const showReplace = onReplace && can.replaceFile;
|
|
62
|
+
const showReplace = (onReplace && can.replaceFile) || (onReplaceEmbed && can.editArticle);
|
|
48
63
|
const replaceBtnText = onDownload ? 'Replace' : 'Choose file';
|
|
49
64
|
const showDelete = () => {
|
|
50
65
|
if (!hasSiblings()) {
|
|
@@ -64,23 +79,25 @@ const FigureOptions = ({ can, getDoc, getFiles, onDownload, onUpload, onDetach,
|
|
|
64
79
|
container.classList.remove(activeClass);
|
|
65
80
|
}
|
|
66
81
|
}, [isOpen, container.classList]);
|
|
82
|
+
const isEmbedMode = !!onReplaceEmbed;
|
|
67
83
|
const groupFiles = (0, files_1.memoGroupFiles)();
|
|
68
84
|
return (react_1.default.createElement(DropdownWrapper, { ref: wrapperRef },
|
|
69
85
|
react_1.default.createElement(OptionsButton, { className: 'options-button', onClick: toggleOpen },
|
|
70
86
|
react_1.default.createElement(style_guide_1.DotsIcon, null)),
|
|
71
87
|
isOpen && (react_1.default.createElement(OptionsDropdownList, { direction: 'right', width: 128, top: 5 },
|
|
72
|
-
react_1.default.createElement(
|
|
73
|
-
|
|
88
|
+
showReplace && isEmbedMode && (react_1.default.createElement(ListItemButton, { onClick: () => onReplaceEmbed && onReplaceEmbed() }, "Edit Link")),
|
|
89
|
+
showReplace && !isEmbedMode && (react_1.default.createElement(NestedDropdown, { disabled: !showReplace, parentToggleOpen: toggleOpen, buttonText: replaceBtnText, moveLeft: true, list: react_1.default.createElement(react_1.default.Fragment, null,
|
|
90
|
+
getSupplements(getFiles, getDoc, groupFiles, isEmbed, currentFileHref).map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file, true) },
|
|
74
91
|
(0, style_guide_1.getFileIcon)(file.name),
|
|
75
92
|
react_1.default.createElement(ListItemText, null, file.name)))),
|
|
76
|
-
getOtherFiles(getFiles, getDoc, groupFiles).map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
|
|
93
|
+
getOtherFiles(getFiles, getDoc, groupFiles, isEmbed, currentFileHref).map((file, index) => (react_1.default.createElement(ListItemButton, { key: file.id, id: index.toString(), onClick: () => onReplace && onReplace(file) },
|
|
77
94
|
(0, style_guide_1.getFileIcon)(file.name),
|
|
78
95
|
react_1.default.createElement(ListItemText, null, file.name)))),
|
|
79
|
-
react_1.default.createElement(UploadButton, { onClick: onUpload, disabled: !showUpload },
|
|
96
|
+
showUpload && (react_1.default.createElement(UploadButton, { onClick: onUpload, disabled: !showUpload },
|
|
80
97
|
react_1.default.createElement(style_guide_1.UploadIcon, null),
|
|
81
|
-
" Upload new...")) }),
|
|
82
|
-
react_1.default.createElement(ListItemButton, { onClick: onDownload, disabled: !showDownload }, "Download"),
|
|
83
|
-
react_1.default.createElement(ListItemButton, { onClick: onDetach, disabled: !showDetach }, "Detach"),
|
|
98
|
+
" Upload new..."))) })),
|
|
99
|
+
showDownload && (react_1.default.createElement(ListItemButton, { onClick: onDownload, disabled: !showDownload }, "Download")),
|
|
100
|
+
showDetach && (react_1.default.createElement(ListItemButton, { onClick: onDetach, disabled: !showDetach }, "Detach")),
|
|
84
101
|
showDelete() && (react_1.default.createElement(ListItemButton, { onClick: onDelete }, "Delete"))))));
|
|
85
102
|
};
|
|
86
103
|
exports.FigureOptions = FigureOptions;
|
|
@@ -61,7 +61,7 @@ exports.default = (props, dispatch) => {
|
|
|
61
61
|
cross_reference: (0, cross_reference_editable_1.default)(props, dispatch),
|
|
62
62
|
contributors: (0, contributors_1.default)(props, dispatch),
|
|
63
63
|
affiliations: (0, affiliations_1.default)(props, dispatch),
|
|
64
|
-
embed: (0, embed_1.default)(props),
|
|
64
|
+
embed: (0, embed_1.default)(props, dispatch),
|
|
65
65
|
equation: (0, equation_editable_1.default)(props),
|
|
66
66
|
equation_element: (0, equation_element_editable_1.default)(props),
|
|
67
67
|
figure: (0, figure_editable_1.default)(props, dispatch),
|
package/dist/cjs/index.js
CHANGED
|
@@ -49,6 +49,7 @@ __exportStar(require("./lib/comments"), exports);
|
|
|
49
49
|
__exportStar(require("./lib/files"), exports);
|
|
50
50
|
__exportStar(require("./lib/footnotes"), exports);
|
|
51
51
|
__exportStar(require("./lib/doc"), exports);
|
|
52
|
+
__exportStar(require("./lib/media"), exports);
|
|
52
53
|
__exportStar(require("./plugins/comments"), exports);
|
|
53
54
|
var selected_suggestion_1 = require("./plugins/selected-suggestion");
|
|
54
55
|
Object.defineProperty(exports, "selectedSuggestionKey", { enumerable: true, get: function () { return selected_suggestion_1.selectedSuggestionKey; } });
|
|
@@ -57,6 +58,7 @@ __exportStar(require("./lib/utils"), exports);
|
|
|
57
58
|
__exportStar(require("./lib/track-changes-utils"), exports);
|
|
58
59
|
__exportStar(require("./useEditor"), exports);
|
|
59
60
|
__exportStar(require("./lib/math"), exports);
|
|
61
|
+
__exportStar(require("./lib/get-media-type"), exports);
|
|
60
62
|
var objects_1 = require("./plugins/objects");
|
|
61
63
|
Object.defineProperty(exports, "objectsPluginKey", { enumerable: true, get: function () { return objects_1.objectsKey; } });
|
|
62
64
|
var footnotes_1 = require("./plugins/footnotes");
|
|
@@ -22,10 +22,9 @@ const prosemirror_utils_1 = require("prosemirror-utils");
|
|
|
22
22
|
const react_1 = require("react");
|
|
23
23
|
const server_1 = require("react-dom/server");
|
|
24
24
|
const commands_1 = require("../commands");
|
|
25
|
-
const image_element_1 = require("../views/image_element");
|
|
26
25
|
const popper_1 = require("./popper");
|
|
26
|
+
const position_menu_1 = require("./position-menu");
|
|
27
27
|
const utils_1 = require("./utils");
|
|
28
|
-
const view_1 = require("./view");
|
|
29
28
|
const popper = new popper_1.PopperManager();
|
|
30
29
|
const readonlyTypes = [
|
|
31
30
|
transform_1.schema.nodes.keywords,
|
|
@@ -159,35 +158,7 @@ class ContextMenu {
|
|
|
159
158
|
const figure = (0, utils_1.getMatchingChild)(this.node, (node) => node.type === transform_1.schema.nodes.figure);
|
|
160
159
|
if (figure) {
|
|
161
160
|
const attrType = figure.attrs.type;
|
|
162
|
-
const submenuOptions =
|
|
163
|
-
{
|
|
164
|
-
title: 'Left',
|
|
165
|
-
action: () => (0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.figure, {
|
|
166
|
-
...figure.attrs,
|
|
167
|
-
type: image_element_1.figurePositions.left,
|
|
168
|
-
}),
|
|
169
|
-
Icon: style_guide_1.ImageLeftIcon,
|
|
170
|
-
selected: attrType === image_element_1.figurePositions.left,
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
title: 'Default',
|
|
174
|
-
action: () => (0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.figure, {
|
|
175
|
-
...figure.attrs,
|
|
176
|
-
type: image_element_1.figurePositions.default,
|
|
177
|
-
}),
|
|
178
|
-
Icon: style_guide_1.ImageDefaultIcon,
|
|
179
|
-
selected: !attrType,
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
title: 'Right',
|
|
183
|
-
action: () => (0, view_1.updateNodeAttrs)(this.view, transform_1.schema.nodes.figure, {
|
|
184
|
-
...figure.attrs,
|
|
185
|
-
type: image_element_1.figurePositions.right,
|
|
186
|
-
}),
|
|
187
|
-
Icon: style_guide_1.ImageRightIcon,
|
|
188
|
-
selected: attrType === image_element_1.figurePositions.right,
|
|
189
|
-
},
|
|
190
|
-
];
|
|
161
|
+
const submenuOptions = (0, position_menu_1.createPositionOptions)(transform_1.schema.nodes.figure, figure, attrType, this.view);
|
|
191
162
|
const submenuLabel = 'Position';
|
|
192
163
|
const submenu = this.createSubmenu(submenuLabel, submenuOptions);
|
|
193
164
|
menu.appendChild(submenu);
|
|
@@ -314,12 +285,17 @@ class ContextMenu {
|
|
|
314
285
|
item.addEventListener('mousedown', this.toggleSubmenu);
|
|
315
286
|
return item;
|
|
316
287
|
};
|
|
317
|
-
this.createMenuItem = (contents, handler,
|
|
288
|
+
this.createMenuItem = (contents, handler, IconComponent = null, selected = false) => {
|
|
318
289
|
const item = document.createElement('div');
|
|
319
290
|
item.className = 'menu-item';
|
|
320
291
|
selected && item.classList.add('selected');
|
|
321
|
-
if (
|
|
322
|
-
|
|
292
|
+
if (IconComponent) {
|
|
293
|
+
if (typeof IconComponent === 'string') {
|
|
294
|
+
item.innerHTML = IconComponent;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
item.innerHTML = (0, server_1.renderToStaticMarkup)((0, react_1.createElement)(IconComponent));
|
|
298
|
+
}
|
|
323
299
|
}
|
|
324
300
|
const textNode = document.createTextNode(contents);
|
|
325
301
|
item.appendChild(textNode);
|
|
@@ -340,8 +316,8 @@ class ContextMenu {
|
|
|
340
316
|
const submenu = document.createElement('div');
|
|
341
317
|
submenu.classList.add('context-submenu');
|
|
342
318
|
submenu.append(this.createSubmenuTrigger(submenuLabel), this.createMenuSection((section) => {
|
|
343
|
-
items.forEach(({ title, action,
|
|
344
|
-
section.appendChild(this.createMenuItem(title, action,
|
|
319
|
+
items.forEach(({ title, action, IconComponent, selected }) => {
|
|
320
|
+
section.appendChild(this.createMenuItem(title, action, IconComponent, selected));
|
|
345
321
|
});
|
|
346
322
|
}, true));
|
|
347
323
|
return submenu;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMediaTypeInfo = void 0;
|
|
4
|
+
const getMediaTypeInfo = (filenameOrFile) => {
|
|
5
|
+
const filename = typeof filenameOrFile === 'string'
|
|
6
|
+
? filenameOrFile
|
|
7
|
+
: filenameOrFile?.name || '';
|
|
8
|
+
const extension = filename.toLowerCase().split('.').pop()?.trim() || '';
|
|
9
|
+
const videoExtensions = new Set([
|
|
10
|
+
'mp4',
|
|
11
|
+
'webm',
|
|
12
|
+
'avi',
|
|
13
|
+
'mov',
|
|
14
|
+
'mkv',
|
|
15
|
+
'flv',
|
|
16
|
+
'wmv',
|
|
17
|
+
'mpg',
|
|
18
|
+
'mpeg',
|
|
19
|
+
]);
|
|
20
|
+
const audioExtensions = new Set([
|
|
21
|
+
'mp3',
|
|
22
|
+
'wav',
|
|
23
|
+
'aac',
|
|
24
|
+
'ogg',
|
|
25
|
+
'flac',
|
|
26
|
+
'm4a',
|
|
27
|
+
'wma',
|
|
28
|
+
]);
|
|
29
|
+
const imageExtensions = new Set([
|
|
30
|
+
'jpg',
|
|
31
|
+
'jpeg',
|
|
32
|
+
'png',
|
|
33
|
+
'gif',
|
|
34
|
+
'bmp',
|
|
35
|
+
'svg',
|
|
36
|
+
'webp',
|
|
37
|
+
'tiff',
|
|
38
|
+
'tif',
|
|
39
|
+
]);
|
|
40
|
+
let mimetype;
|
|
41
|
+
let mimeSubtype;
|
|
42
|
+
if (typeof filenameOrFile !== 'string' && filenameOrFile?.type) {
|
|
43
|
+
const [type, subtype] = filenameOrFile.type.split('/');
|
|
44
|
+
if (type && subtype && ['video', 'audio', 'image'].includes(type)) {
|
|
45
|
+
mimetype = type;
|
|
46
|
+
mimeSubtype = subtype;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!mimetype || !mimeSubtype) {
|
|
50
|
+
if (videoExtensions.has(extension)) {
|
|
51
|
+
mimetype = 'video';
|
|
52
|
+
mimeSubtype = extension === 'mov' ? 'quicktime' : extension;
|
|
53
|
+
}
|
|
54
|
+
else if (audioExtensions.has(extension)) {
|
|
55
|
+
mimetype = 'audio';
|
|
56
|
+
mimeSubtype = extension === 'm4a' ? 'mp4' : extension;
|
|
57
|
+
}
|
|
58
|
+
else if (imageExtensions.has(extension)) {
|
|
59
|
+
mimetype = 'image';
|
|
60
|
+
mimeSubtype = extension === 'jpg' ? 'jpeg' : extension;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const isVideo = mimetype === 'video' || videoExtensions.has(extension);
|
|
64
|
+
const isAudio = mimetype === 'audio' || audioExtensions.has(extension);
|
|
65
|
+
const isImage = mimetype === 'image' || imageExtensions.has(extension);
|
|
66
|
+
const isSupported = isVideo || isAudio || isImage;
|
|
67
|
+
return {
|
|
68
|
+
extension,
|
|
69
|
+
isVideo,
|
|
70
|
+
isAudio,
|
|
71
|
+
isImage,
|
|
72
|
+
isSupported,
|
|
73
|
+
mimetype,
|
|
74
|
+
mimeSubtype,
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
exports.getMediaTypeInfo = getMediaTypeInfo;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* © 2019 Atypon Systems LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.addInteractionHandlers = exports.createFileUploader = exports.createReactTools = exports.createFileHandlers = exports.createMediaPlaceholder = exports.createUnsupportedFormat = void 0;
|
|
22
|
+
const transform_1 = require("@manuscripts/transform");
|
|
23
|
+
const InsertEmbedDialog_1 = require("../components/toolbar/InsertEmbedDialog");
|
|
24
|
+
const FigureDropdown_1 = require("../components/views/FigureDropdown");
|
|
25
|
+
const icons_1 = require("../icons");
|
|
26
|
+
const ReactSubView_1 = __importDefault(require("../views/ReactSubView"));
|
|
27
|
+
const createUnsupportedFormat = (filename, canEdit) => {
|
|
28
|
+
const element = document.createElement('div');
|
|
29
|
+
element.classList.add('figure', 'placeholder');
|
|
30
|
+
const instructions = document.createElement('div');
|
|
31
|
+
instructions.classList.add('instructions');
|
|
32
|
+
const iconHtml = icons_1.fileCorruptedIcon;
|
|
33
|
+
instructions.innerHTML = `
|
|
34
|
+
<div>
|
|
35
|
+
<div class="unsupported-icon-wrapper">${iconHtml}</div>
|
|
36
|
+
<div>${filename}</div>
|
|
37
|
+
<div class="unsupported-format-label">
|
|
38
|
+
Unsupported file format
|
|
39
|
+
</div>
|
|
40
|
+
<div>
|
|
41
|
+
${canEdit ? 'Click to add media' : 'No media here yet…'}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
`;
|
|
45
|
+
element.appendChild(instructions);
|
|
46
|
+
return element;
|
|
47
|
+
};
|
|
48
|
+
exports.createUnsupportedFormat = createUnsupportedFormat;
|
|
49
|
+
const createMediaPlaceholder = (mediaType = 'media', view, getPos) => {
|
|
50
|
+
const element = document.createElement('div');
|
|
51
|
+
element.classList.add('figure', 'placeholder');
|
|
52
|
+
const instructions = document.createElement('div');
|
|
53
|
+
instructions.classList.add('instructions');
|
|
54
|
+
const uploadText = mediaType === 'media' ? 'media' : 'image';
|
|
55
|
+
instructions.innerHTML = `
|
|
56
|
+
<div class="placeholder-content">
|
|
57
|
+
<p>Drag or click here to upload ${uploadText} <br>
|
|
58
|
+
or drag items here from the file inspector tabs <br>
|
|
59
|
+
<a data-action='open-other-files'>'Other files'</a> |
|
|
60
|
+
<a data-action='open-supplement-files'>'Supplements'</a>
|
|
61
|
+
${mediaType === 'media' && view && getPos
|
|
62
|
+
? "| <a data-action='add-external-link'>'External link'</a>"
|
|
63
|
+
: ''}
|
|
64
|
+
</p>
|
|
65
|
+
</div>
|
|
66
|
+
`;
|
|
67
|
+
if (mediaType === 'media' && view && getPos) {
|
|
68
|
+
const embedLink = instructions.querySelector("[data-action='add-external-link']");
|
|
69
|
+
if (embedLink) {
|
|
70
|
+
embedLink.addEventListener('click', (e) => {
|
|
71
|
+
e.stopPropagation();
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
(0, InsertEmbedDialog_1.openEmbedDialog)(view, getPos());
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
element.appendChild(instructions);
|
|
78
|
+
return element;
|
|
79
|
+
};
|
|
80
|
+
exports.createMediaPlaceholder = createMediaPlaceholder;
|
|
81
|
+
const createFileHandlers = (node, view, getPos, props, setHref) => {
|
|
82
|
+
const handlers = {};
|
|
83
|
+
const href = node.attrs.href;
|
|
84
|
+
const files = props.getFiles();
|
|
85
|
+
const file = href && files.find((f) => f.id === href);
|
|
86
|
+
const can = props.getCapabilities();
|
|
87
|
+
if (href && file) {
|
|
88
|
+
handlers.handleDownload = () => {
|
|
89
|
+
props.fileManagement.download(file);
|
|
90
|
+
};
|
|
91
|
+
handlers.handleDetach = () => {
|
|
92
|
+
setHref('');
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (can.replaceFile) {
|
|
96
|
+
handlers.handleReplace = (file, isSupplement = false) => {
|
|
97
|
+
setHref(file.id);
|
|
98
|
+
if (isSupplement) {
|
|
99
|
+
const tr = view.state.tr;
|
|
100
|
+
view.state.doc.descendants((node, pos) => {
|
|
101
|
+
if (node.type === transform_1.schema.nodes.supplement) {
|
|
102
|
+
const href = node.attrs.href;
|
|
103
|
+
if (href === file.id) {
|
|
104
|
+
tr.delete(pos, pos + node.nodeSize);
|
|
105
|
+
view.dispatch(tr);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (node.type !== transform_1.schema.nodes.supplements &&
|
|
109
|
+
node.type !== transform_1.schema.nodes.manuscript) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return handlers;
|
|
117
|
+
};
|
|
118
|
+
exports.createFileHandlers = createFileHandlers;
|
|
119
|
+
const createReactTools = (node, view, getPos, props, handlers, isEmbed, hasSiblings) => {
|
|
120
|
+
if (!props.dispatch || !props.theme) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const can = props.getCapabilities();
|
|
124
|
+
const currentFileHref = node.attrs.href;
|
|
125
|
+
const componentProps = {
|
|
126
|
+
can,
|
|
127
|
+
getDoc: () => view.state.doc,
|
|
128
|
+
getFiles: props.getFiles,
|
|
129
|
+
onDownload: handlers.handleDownload,
|
|
130
|
+
onUpload: handlers.handleUpload,
|
|
131
|
+
onDetach: handlers.handleDetach,
|
|
132
|
+
onReplace: handlers.handleReplace,
|
|
133
|
+
onReplaceEmbed: handlers.handleReplaceEmbed,
|
|
134
|
+
onDelete: handlers.handleDelete,
|
|
135
|
+
isEmbed,
|
|
136
|
+
hasSiblings,
|
|
137
|
+
currentFileHref,
|
|
138
|
+
};
|
|
139
|
+
return (0, ReactSubView_1.default)(props, FigureDropdown_1.FigureOptions, componentProps, node, getPos, view);
|
|
140
|
+
};
|
|
141
|
+
exports.createReactTools = createReactTools;
|
|
142
|
+
const createFileUploader = (handler, accept = '*/*') => {
|
|
143
|
+
const handleFileChange = async (e) => {
|
|
144
|
+
const target = e.target;
|
|
145
|
+
if (target && target.files && target.files.length) {
|
|
146
|
+
await handler(target.files[0]);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const input = document.createElement('input');
|
|
150
|
+
input.accept = accept;
|
|
151
|
+
input.type = 'file';
|
|
152
|
+
input.addEventListener('change', handleFileChange);
|
|
153
|
+
return () => input.click();
|
|
154
|
+
};
|
|
155
|
+
exports.createFileUploader = createFileUploader;
|
|
156
|
+
const addInteractionHandlers = (element, uploadFn, accept = '*/*') => {
|
|
157
|
+
const handlePlaceholderClick = (event) => {
|
|
158
|
+
const target = event.target;
|
|
159
|
+
if (target.dataset && target.dataset.action) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const input = document.createElement('input');
|
|
163
|
+
input.type = 'file';
|
|
164
|
+
input.accept = accept;
|
|
165
|
+
input.addEventListener('change', async (e) => {
|
|
166
|
+
const files = e.target.files;
|
|
167
|
+
if (files && files.length > 0) {
|
|
168
|
+
await uploadFn(files[0]);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
input.click();
|
|
172
|
+
};
|
|
173
|
+
element.addEventListener('click', handlePlaceholderClick);
|
|
174
|
+
element.addEventListener('mouseenter', () => {
|
|
175
|
+
element.classList.toggle('over', true);
|
|
176
|
+
});
|
|
177
|
+
element.addEventListener('mouseleave', () => {
|
|
178
|
+
element.classList.toggle('over', false);
|
|
179
|
+
});
|
|
180
|
+
element.addEventListener('dragenter', (event) => {
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
element.classList.toggle('over', true);
|
|
183
|
+
});
|
|
184
|
+
element.addEventListener('dragleave', (event) => {
|
|
185
|
+
event.preventDefault();
|
|
186
|
+
element.classList.toggle('over', false);
|
|
187
|
+
});
|
|
188
|
+
element.addEventListener('dragover', (e) => {
|
|
189
|
+
const dragEvent = e;
|
|
190
|
+
if (dragEvent.dataTransfer && dragEvent.dataTransfer.items) {
|
|
191
|
+
for (const item of dragEvent.dataTransfer.items) {
|
|
192
|
+
if (item.kind === 'file') {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
dragEvent.dataTransfer.dropEffect = 'copy';
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
element.addEventListener('drop', async (e) => {
|
|
201
|
+
if (e.dataTransfer && e.dataTransfer.files.length) {
|
|
202
|
+
e.preventDefault();
|
|
203
|
+
await uploadFn(e.dataTransfer.files[0]);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
exports.addInteractionHandlers = addInteractionHandlers;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* © 2025 Atypon Systems LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.createPositionMenuWrapper = exports.setElementPositionAlignment = exports.showPositionMenu = exports.createPopperMenuPositionOptions = exports.createPositionOptions = void 0;
|
|
22
|
+
const style_guide_1 = require("@manuscripts/style-guide");
|
|
23
|
+
const icons_1 = require("../icons");
|
|
24
|
+
const image_element_1 = require("../views/image_element");
|
|
25
|
+
const ReactSubView_1 = __importDefault(require("../views/ReactSubView"));
|
|
26
|
+
const view_1 = require("./view");
|
|
27
|
+
const createPositionOptions = (nodeType, node, currentPosition, view, onComplete) => {
|
|
28
|
+
const createAction = (position) => () => {
|
|
29
|
+
onComplete?.();
|
|
30
|
+
(0, view_1.updateNodeAttrs)(view, nodeType, {
|
|
31
|
+
...node.attrs,
|
|
32
|
+
type: position,
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
return [
|
|
36
|
+
{
|
|
37
|
+
title: 'Left',
|
|
38
|
+
action: createAction(image_element_1.figurePositions.left),
|
|
39
|
+
IconComponent: icons_1.imageLeftIcon,
|
|
40
|
+
iconName: 'ImageLeft',
|
|
41
|
+
selected: currentPosition === image_element_1.figurePositions.left,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
title: 'Center',
|
|
45
|
+
action: createAction(image_element_1.figurePositions.default),
|
|
46
|
+
IconComponent: icons_1.imageDefaultIcon,
|
|
47
|
+
iconName: 'ImageDefault',
|
|
48
|
+
selected: !currentPosition,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: 'Right',
|
|
52
|
+
action: createAction(image_element_1.figurePositions.right),
|
|
53
|
+
IconComponent: icons_1.imageRightIcon,
|
|
54
|
+
iconName: 'ImageRight',
|
|
55
|
+
selected: currentPosition === image_element_1.figurePositions.right,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
};
|
|
59
|
+
exports.createPositionOptions = createPositionOptions;
|
|
60
|
+
const createPopperMenuPositionOptions = (nodeType, node, currentPosition, view, onComplete) => {
|
|
61
|
+
return (0, exports.createPositionOptions)(nodeType, node, currentPosition, view, onComplete).map((option) => ({
|
|
62
|
+
label: option.title,
|
|
63
|
+
action: option.action,
|
|
64
|
+
icon: option.iconName,
|
|
65
|
+
selected: option.selected,
|
|
66
|
+
}));
|
|
67
|
+
};
|
|
68
|
+
exports.createPopperMenuPositionOptions = createPopperMenuPositionOptions;
|
|
69
|
+
const showPositionMenu = (nodeType, node, currentPosition, positionMenuWrapper, view, getPos, props) => {
|
|
70
|
+
props.popper.destroy();
|
|
71
|
+
const options = (0, exports.createPopperMenuPositionOptions)(nodeType, node, currentPosition, view, () => props.popper.destroy());
|
|
72
|
+
const componentProps = {
|
|
73
|
+
actions: options,
|
|
74
|
+
};
|
|
75
|
+
props.popper.show(positionMenuWrapper, (0, ReactSubView_1.default)(props, style_guide_1.ContextMenu, componentProps, node, getPos, view, [
|
|
76
|
+
'context-menu',
|
|
77
|
+
'position-menu',
|
|
78
|
+
]), 'left', false);
|
|
79
|
+
};
|
|
80
|
+
exports.showPositionMenu = showPositionMenu;
|
|
81
|
+
const setElementPositionAlignment = (element, position) => {
|
|
82
|
+
switch (position) {
|
|
83
|
+
case image_element_1.figurePositions.left:
|
|
84
|
+
element.setAttribute('data-alignment', 'left');
|
|
85
|
+
break;
|
|
86
|
+
case image_element_1.figurePositions.right:
|
|
87
|
+
element.setAttribute('data-alignment', 'right');
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
element.removeAttribute('data-alignment');
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
exports.setElementPositionAlignment = setElementPositionAlignment;
|
|
95
|
+
const createPositionMenuWrapper = (currentPosition, onClick, props) => {
|
|
96
|
+
const can = props.getCapabilities();
|
|
97
|
+
const positionMenuWrapper = document.createElement('div');
|
|
98
|
+
positionMenuWrapper.classList.add('position-menu');
|
|
99
|
+
const positionMenuButton = document.createElement('div');
|
|
100
|
+
positionMenuButton.classList.add('position-menu-button');
|
|
101
|
+
let icon;
|
|
102
|
+
switch (currentPosition) {
|
|
103
|
+
case image_element_1.figurePositions.left:
|
|
104
|
+
icon = icons_1.imageLeftIcon;
|
|
105
|
+
break;
|
|
106
|
+
case image_element_1.figurePositions.right:
|
|
107
|
+
icon = icons_1.imageRightIcon;
|
|
108
|
+
break;
|
|
109
|
+
default:
|
|
110
|
+
icon = icons_1.imageDefaultIcon;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (icon) {
|
|
114
|
+
positionMenuButton.innerHTML = icon;
|
|
115
|
+
}
|
|
116
|
+
if (can.editArticle) {
|
|
117
|
+
positionMenuButton.addEventListener('click', onClick);
|
|
118
|
+
}
|
|
119
|
+
positionMenuWrapper.appendChild(positionMenuButton);
|
|
120
|
+
return positionMenuWrapper;
|
|
121
|
+
};
|
|
122
|
+
exports.createPositionMenuWrapper = createPositionMenuWrapper;
|