@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/menus.js
CHANGED
|
@@ -20,7 +20,6 @@ const transform_1 = require("@manuscripts/transform");
|
|
|
20
20
|
const prosemirror_commands_1 = require("prosemirror-commands");
|
|
21
21
|
const prosemirror_history_1 = require("prosemirror-history");
|
|
22
22
|
const commands_1 = require("./commands");
|
|
23
|
-
const InsertEmbedDialog_1 = require("./components/toolbar/InsertEmbedDialog");
|
|
24
23
|
const InsertTableDialog_1 = require("./components/toolbar/InsertTableDialog");
|
|
25
24
|
const ListMenuItem_1 = require("./components/toolbar/ListMenuItem");
|
|
26
25
|
const InsertSpecialCharacter_1 = require("./components/views/InsertSpecialCharacter");
|
|
@@ -263,7 +262,7 @@ const getEditorMenus = (editor) => {
|
|
|
263
262
|
label: 'Embedded Media',
|
|
264
263
|
isActive: (0, commands_1.blockActive)(transform_1.schema.nodes.embed)(state),
|
|
265
264
|
isEnabled: (0, utils_1.isEditAllowed)(state) && isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.embed)),
|
|
266
|
-
run: (
|
|
265
|
+
run: doCommand(commands_1.insertEmbed),
|
|
267
266
|
},
|
|
268
267
|
{
|
|
269
268
|
id: 'insert-link',
|
package/dist/cjs/versions.js
CHANGED
package/dist/cjs/views/embed.js
CHANGED
|
@@ -1,101 +1,225 @@
|
|
|
1
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
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
4
|
};
|
|
20
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.
|
|
22
|
-
const
|
|
23
|
-
const
|
|
6
|
+
exports.EmbedView = void 0;
|
|
7
|
+
const lodash_1 = require("lodash");
|
|
8
|
+
const prosemirror_state_1 = require("prosemirror-state");
|
|
24
9
|
const InsertEmbedDialog_1 = require("../components/toolbar/InsertEmbedDialog");
|
|
25
|
-
const
|
|
10
|
+
const get_media_type_1 = require("../lib/get-media-type");
|
|
11
|
+
const media_1 = require("../lib/media");
|
|
26
12
|
const oembed_1 = require("../lib/oembed");
|
|
13
|
+
const url_1 = require("../lib/url");
|
|
27
14
|
const block_view_1 = __importDefault(require("./block_view"));
|
|
28
15
|
const creators_1 = require("./creators");
|
|
16
|
+
const editable_block_1 = require("./editable_block");
|
|
29
17
|
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
30
|
-
class
|
|
18
|
+
class EmbedView extends block_view_1.default {
|
|
31
19
|
constructor() {
|
|
32
20
|
super(...arguments);
|
|
21
|
+
this.preview = null;
|
|
22
|
+
this.reactTools = null;
|
|
33
23
|
this.ignoreMutation = () => true;
|
|
34
|
-
this.
|
|
24
|
+
this.initialized = false;
|
|
25
|
+
this.previousAttrs = {};
|
|
35
26
|
this.createElement = () => {
|
|
36
27
|
this.container = document.createElement('div');
|
|
37
28
|
this.container.classList.add('block');
|
|
38
29
|
this.dom.appendChild(this.container);
|
|
30
|
+
const figureBlock = document.createElement('div');
|
|
31
|
+
figureBlock.classList.add('figure-block');
|
|
32
|
+
this.container.appendChild(figureBlock);
|
|
39
33
|
this.contentDOM = document.createElement('div');
|
|
40
|
-
|
|
41
|
-
this.
|
|
34
|
+
figureBlock.appendChild(this.contentDOM);
|
|
35
|
+
this.figureBlock = figureBlock;
|
|
42
36
|
};
|
|
43
|
-
this.
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
this.upload = async (file) => {
|
|
38
|
+
const mediaInfo = (0, get_media_type_1.getMediaTypeInfo)(file);
|
|
39
|
+
const result = await this.props.fileManagement.upload(file);
|
|
40
|
+
const pos = this.getPos();
|
|
41
|
+
const tr = this.view.state.tr;
|
|
42
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
43
|
+
...this.node.attrs,
|
|
44
|
+
href: result.id,
|
|
45
|
+
mimetype: mediaInfo.mimetype,
|
|
46
|
+
mimeSubtype: mediaInfo.mimeSubtype,
|
|
47
|
+
});
|
|
48
|
+
this.view.dispatch(tr);
|
|
49
|
+
};
|
|
50
|
+
this.setHref = (href) => {
|
|
51
|
+
const { tr } = this.view.state;
|
|
52
|
+
const pos = this.getPos();
|
|
53
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
54
|
+
...this.node.attrs,
|
|
55
|
+
href: href,
|
|
56
|
+
});
|
|
57
|
+
tr.setSelection(prosemirror_state_1.NodeSelection.create(tr.doc, pos));
|
|
58
|
+
this.view.dispatch(tr);
|
|
59
|
+
};
|
|
60
|
+
this.createMedia = () => {
|
|
61
|
+
const { href } = this.node.attrs;
|
|
62
|
+
if (!href) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const files = this.props.getFiles();
|
|
66
|
+
const file = files.find((f) => f.id === href);
|
|
67
|
+
if (!file) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const mediaUrl = file.link || file.id;
|
|
71
|
+
if (!mediaUrl) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const mediaInfo = (0, get_media_type_1.getMediaTypeInfo)(file.name);
|
|
75
|
+
if (mediaInfo.isVideo) {
|
|
76
|
+
const video = document.createElement('video');
|
|
77
|
+
video.controls = true;
|
|
78
|
+
video.style.maxWidth = '100%';
|
|
79
|
+
video.style.height = '250px';
|
|
80
|
+
const source = document.createElement('source');
|
|
81
|
+
source.src = mediaUrl;
|
|
82
|
+
video.appendChild(source);
|
|
83
|
+
video.appendChild(document.createTextNode('Your browser does not support the video tag.'));
|
|
84
|
+
return video;
|
|
85
|
+
}
|
|
86
|
+
else if (mediaInfo.isAudio) {
|
|
87
|
+
const audio = document.createElement('audio');
|
|
88
|
+
audio.controls = true;
|
|
89
|
+
audio.style.width = '100%';
|
|
90
|
+
const source = document.createElement('source');
|
|
91
|
+
source.src = mediaUrl;
|
|
92
|
+
audio.appendChild(source);
|
|
93
|
+
audio.appendChild(document.createTextNode('Your browser does not support the audio tag.'));
|
|
94
|
+
return audio;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return (0, media_1.createUnsupportedFormat)(file.name, this.props.getCapabilities().editArticle);
|
|
47
98
|
}
|
|
48
|
-
const componentProps = {
|
|
49
|
-
actions: [
|
|
50
|
-
{
|
|
51
|
-
label: 'Comment',
|
|
52
|
-
action: () => (0, commands_1.addNodeComment)(this.node, this.view.state, this.view.dispatch),
|
|
53
|
-
icon: 'AddComment',
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
label: 'Delete',
|
|
57
|
-
action: () => (0, DeleteEmbedDialog_1.openDeleteEmbedDialog)(this.view, this.node, this.getPos()),
|
|
58
|
-
icon: 'Delete',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
label: 'Edit',
|
|
62
|
-
action: () => (0, InsertEmbedDialog_1.openEmbedDialog)(this.view, this.getPos()),
|
|
63
|
-
icon: 'Edit',
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
};
|
|
67
|
-
preview.appendChild((0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['embed-context-menu']));
|
|
68
99
|
};
|
|
69
100
|
}
|
|
70
|
-
|
|
101
|
+
updateContents() {
|
|
71
102
|
super.updateContents();
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
103
|
+
const { href, mimetype, mimeSubtype } = this.node.attrs;
|
|
104
|
+
const currentAttrs = { href, mimetype, mimeSubtype };
|
|
105
|
+
const contentChanged = !this.initialized || !(0, lodash_1.isEqual)(this.previousAttrs, currentAttrs);
|
|
106
|
+
if (contentChanged) {
|
|
107
|
+
this.initialized = true;
|
|
108
|
+
this.previousAttrs = currentAttrs;
|
|
109
|
+
this.updateMediaPreview();
|
|
110
|
+
this.manageReactTools();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
manageReactTools() {
|
|
114
|
+
this.reactTools?.remove();
|
|
115
|
+
let handlers;
|
|
116
|
+
const can = this.props.getCapabilities();
|
|
117
|
+
if (this.isUploadedFile()) {
|
|
118
|
+
handlers = (0, media_1.createFileHandlers)(this.node, this.view, this.getPos, this.props, this.setHref);
|
|
119
|
+
if (can.uploadFile) {
|
|
120
|
+
handlers.handleUpload = (0, media_1.createFileUploader)(this.upload, 'video/*,audio/*');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (this.isEmbedLink()) {
|
|
124
|
+
handlers = this.createEmbedHandlers();
|
|
125
|
+
}
|
|
126
|
+
if (handlers) {
|
|
127
|
+
this.reactTools = (0, media_1.createReactTools)(this.node, this.view, this.getPos, this.props, handlers, true, () => false);
|
|
128
|
+
if (this.reactTools) {
|
|
129
|
+
if (this.preview) {
|
|
130
|
+
this.preview.insertBefore(this.reactTools, this.preview.firstChild);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.dom.insertBefore(this.reactTools, this.dom.firstChild);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
isUploadedFile() {
|
|
139
|
+
const { href } = this.node.attrs;
|
|
140
|
+
if (!href) {
|
|
141
|
+
return false;
|
|
75
142
|
}
|
|
143
|
+
const files = this.props.getFiles();
|
|
144
|
+
return files.some((file) => file.id === href);
|
|
145
|
+
}
|
|
146
|
+
isEmbedLink() {
|
|
147
|
+
const { href } = this.node.attrs;
|
|
148
|
+
return !!(href && (0, url_1.allowedHref)(href) && !this.isUploadedFile());
|
|
76
149
|
}
|
|
77
|
-
async
|
|
150
|
+
async updateMediaPreview() {
|
|
78
151
|
const preview = document.createElement('div');
|
|
79
|
-
preview.classList.add('
|
|
152
|
+
preview.classList.add('media-preview');
|
|
80
153
|
preview.setAttribute('contenteditable', 'false');
|
|
81
|
-
const oldPreview = this.
|
|
154
|
+
const oldPreview = this.preview
|
|
155
|
+
? this.preview
|
|
156
|
+
: this.figureBlock.querySelector('.media-preview');
|
|
82
157
|
if (oldPreview) {
|
|
83
|
-
this.
|
|
158
|
+
this.figureBlock.replaceChild(preview, oldPreview);
|
|
84
159
|
}
|
|
85
160
|
else {
|
|
86
|
-
this.
|
|
161
|
+
this.figureBlock.prepend(preview);
|
|
87
162
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
163
|
+
this.preview = preview;
|
|
164
|
+
const href = this.node.attrs.href;
|
|
165
|
+
let object;
|
|
166
|
+
if (!href) {
|
|
167
|
+
object = (0, media_1.createMediaPlaceholder)('media', this.view, this.getPos);
|
|
168
|
+
}
|
|
169
|
+
else if (this.isUploadedFile()) {
|
|
170
|
+
const files = this.props.getFiles();
|
|
171
|
+
const file = files.find((f) => f.id === href);
|
|
172
|
+
if (file) {
|
|
173
|
+
const mediaInfo = (0, get_media_type_1.getMediaTypeInfo)(file.name);
|
|
174
|
+
const isValidMediaFile = mediaInfo.isAudio || mediaInfo.isVideo;
|
|
175
|
+
object = isValidMediaFile
|
|
176
|
+
? this.createMedia() ||
|
|
177
|
+
(0, media_1.createUnsupportedFormat)(file.name, this.props.getCapabilities().editArticle)
|
|
178
|
+
: (0, media_1.createUnsupportedFormat)(file.name, this.props.getCapabilities().editArticle);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
object = (0, media_1.createMediaPlaceholder)('media', this.view, this.getPos);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (this.isEmbedLink()) {
|
|
185
|
+
object = await this.createEmbedPreview();
|
|
91
186
|
}
|
|
92
187
|
else {
|
|
93
|
-
this.
|
|
188
|
+
object = (0, media_1.createMediaPlaceholder)('media', this.view, this.getPos);
|
|
189
|
+
}
|
|
190
|
+
const can = this.props.getCapabilities();
|
|
191
|
+
if (can.uploadFile && object.classList.contains('placeholder')) {
|
|
192
|
+
(0, media_1.addInteractionHandlers)(object, this.upload, 'video/*,audio/*');
|
|
193
|
+
}
|
|
194
|
+
preview.appendChild(object);
|
|
195
|
+
}
|
|
196
|
+
createEmbedHandlers() {
|
|
197
|
+
const handlers = {};
|
|
198
|
+
handlers.handleReplaceEmbed = () => {
|
|
199
|
+
(0, InsertEmbedDialog_1.openEmbedDialog)(this.view, this.getPos());
|
|
200
|
+
};
|
|
201
|
+
return handlers;
|
|
202
|
+
}
|
|
203
|
+
async createEmbedPreview() {
|
|
204
|
+
const container = document.createElement('div');
|
|
205
|
+
container.classList.add('embed-preview');
|
|
206
|
+
try {
|
|
207
|
+
const html = await (0, oembed_1.getOEmbedHTML)(this.node.attrs.href, 643, 363);
|
|
208
|
+
if (html) {
|
|
209
|
+
container.innerHTML = html;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
this.showUnavailableMessage(container);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
this.showUnavailableMessage(container);
|
|
94
217
|
}
|
|
218
|
+
return container;
|
|
95
219
|
}
|
|
96
|
-
showUnavailableMessage(
|
|
97
|
-
|
|
220
|
+
showUnavailableMessage(container) {
|
|
221
|
+
container.appendChild((0, ReactSubView_1.default)(this.props, InsertEmbedDialog_1.NoPreviewMessageWithLink, { href: this.node.attrs.href }, this.node, this.getPos, this.view));
|
|
98
222
|
}
|
|
99
223
|
}
|
|
100
|
-
exports.
|
|
101
|
-
exports.default = (0, creators_1.
|
|
224
|
+
exports.EmbedView = EmbedView;
|
|
225
|
+
exports.default = (0, creators_1.createEditableNodeView)((0, editable_block_1.EditableBlock)(EmbedView));
|
|
@@ -14,24 +14,20 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
-
};
|
|
20
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
18
|
exports.FigureEditableView = void 0;
|
|
22
19
|
const transform_1 = require("@manuscripts/transform");
|
|
23
20
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
24
21
|
const prosemirror_utils_1 = require("prosemirror-utils");
|
|
25
|
-
const FigureDropdown_1 = require("../components/views/FigureDropdown");
|
|
26
22
|
const icons_1 = require("../icons");
|
|
23
|
+
const media_1 = require("../lib/media");
|
|
27
24
|
const track_changes_utils_1 = require("../lib/track-changes-utils");
|
|
28
25
|
const creators_1 = require("./creators");
|
|
29
26
|
const figure_1 = require("./figure");
|
|
30
|
-
const figure_uploader_1 = require("./figure_uploader");
|
|
31
|
-
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
32
27
|
class FigureEditableView extends figure_1.FigureView {
|
|
33
28
|
constructor() {
|
|
34
29
|
super(...arguments);
|
|
30
|
+
this.reactTools = null;
|
|
35
31
|
this.dragAndDropInitialized = false;
|
|
36
32
|
this.upload = async (file) => {
|
|
37
33
|
const result = await this.props.fileManagement.upload(file);
|
|
@@ -48,27 +44,7 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
48
44
|
this.view.dispatch(tr);
|
|
49
45
|
};
|
|
50
46
|
this.createUnsupportedFormat = (name) => {
|
|
51
|
-
|
|
52
|
-
element.classList.add('figure', 'placeholder');
|
|
53
|
-
const instructions = document.createElement('div');
|
|
54
|
-
instructions.classList.add('instructions');
|
|
55
|
-
const iconHtml = icons_1.fileCorruptedIcon;
|
|
56
|
-
instructions.innerHTML = `
|
|
57
|
-
<div>
|
|
58
|
-
<div class="unsupported-icon-wrapper">${iconHtml}</div>
|
|
59
|
-
<div>${name}</div>
|
|
60
|
-
<div class="unsupported-format-label">
|
|
61
|
-
Unsupported file format
|
|
62
|
-
</div>
|
|
63
|
-
<div>
|
|
64
|
-
${this.props.getCapabilities()?.editArticle
|
|
65
|
-
? 'Click to add image'
|
|
66
|
-
: 'No image here yet…'}
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
`;
|
|
70
|
-
element.appendChild(instructions);
|
|
71
|
-
return element;
|
|
47
|
+
return (0, media_1.createUnsupportedFormat)(name, this.props.getCapabilities().editArticle);
|
|
72
48
|
};
|
|
73
49
|
this.createImg = (src) => {
|
|
74
50
|
const img = document.createElement('img');
|
|
@@ -77,18 +53,7 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
77
53
|
return img;
|
|
78
54
|
};
|
|
79
55
|
this.createPlaceholder = () => {
|
|
80
|
-
|
|
81
|
-
element.classList.add('figure', 'placeholder');
|
|
82
|
-
const instructions = document.createElement('div');
|
|
83
|
-
instructions.classList.add('instructions');
|
|
84
|
-
instructions.innerHTML = `
|
|
85
|
-
<p>Drag or click here to upload image <br>
|
|
86
|
-
or drag items here from the file inspector tabs <br>
|
|
87
|
-
<a data-action='open-other-files'>'Other files'</a> |
|
|
88
|
-
<a data-action='open-supplement-files'>'Supplements'</a></p>
|
|
89
|
-
`;
|
|
90
|
-
element.appendChild(instructions);
|
|
91
|
-
return element;
|
|
56
|
+
return (0, media_1.createMediaPlaceholder)('figure');
|
|
92
57
|
};
|
|
93
58
|
}
|
|
94
59
|
initialise() {
|
|
@@ -218,44 +183,7 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
218
183
|
? this.createUnsupportedFormat(file.name)
|
|
219
184
|
: this.createPlaceholder();
|
|
220
185
|
if (can.uploadFile && !(0, track_changes_utils_1.isDeleted)(this.node)) {
|
|
221
|
-
|
|
222
|
-
const target = event.target;
|
|
223
|
-
if (target.dataset && target.dataset.action) {
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
const triggerUpload = (0, figure_uploader_1.figureUploader)(this.upload);
|
|
227
|
-
triggerUpload();
|
|
228
|
-
};
|
|
229
|
-
img.addEventListener('click', handlePlaceholderClick);
|
|
230
|
-
img.addEventListener('mouseenter', () => {
|
|
231
|
-
img.classList.toggle('over', true);
|
|
232
|
-
});
|
|
233
|
-
img.addEventListener('mouseleave', () => {
|
|
234
|
-
img.classList.toggle('over', false);
|
|
235
|
-
});
|
|
236
|
-
img.addEventListener('dragenter', (event) => {
|
|
237
|
-
event.preventDefault();
|
|
238
|
-
img.classList.toggle('over', true);
|
|
239
|
-
});
|
|
240
|
-
img.addEventListener('dragleave', () => {
|
|
241
|
-
img.classList.toggle('over', false);
|
|
242
|
-
});
|
|
243
|
-
img.addEventListener('dragover', (e) => {
|
|
244
|
-
if (e.dataTransfer && e.dataTransfer.items) {
|
|
245
|
-
for (const item of e.dataTransfer.items) {
|
|
246
|
-
if (item.kind === 'file' && item.type.startsWith('image/')) {
|
|
247
|
-
e.preventDefault();
|
|
248
|
-
e.dataTransfer.dropEffect = 'copy';
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
img.addEventListener('drop', async (e) => {
|
|
254
|
-
if (e.dataTransfer && e.dataTransfer.files.length) {
|
|
255
|
-
e.preventDefault();
|
|
256
|
-
await this.upload(e.dataTransfer.files[0]);
|
|
257
|
-
}
|
|
258
|
-
});
|
|
186
|
+
(0, media_1.addInteractionHandlers)(img, this.upload, 'image/*');
|
|
259
187
|
}
|
|
260
188
|
this.container.innerHTML = '';
|
|
261
189
|
this.container.appendChild(img);
|
|
@@ -289,73 +217,22 @@ class FigureEditableView extends figure_1.FigureView {
|
|
|
289
217
|
return count;
|
|
290
218
|
}
|
|
291
219
|
manageReactTools() {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
let handleReplace;
|
|
295
|
-
let handleDetach;
|
|
296
|
-
let handleDelete;
|
|
297
|
-
const src = this.node.attrs.src;
|
|
298
|
-
const files = this.props.getFiles();
|
|
299
|
-
const file = src && files.filter((f) => f.id === src)[0];
|
|
220
|
+
this.reactTools?.remove();
|
|
221
|
+
const handlers = (0, media_1.createFileHandlers)(this.node, this.view, this.getPos, this.props, this.setSrc);
|
|
300
222
|
const can = this.props.getCapabilities();
|
|
301
|
-
if (src) {
|
|
302
|
-
if (file) {
|
|
303
|
-
handleDownload = () => {
|
|
304
|
-
this.props.fileManagement.download(file);
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
handleDetach = () => {
|
|
308
|
-
this.setSrc('');
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
if (can.replaceFile) {
|
|
312
|
-
handleReplace = (file, isSupplement = false) => {
|
|
313
|
-
this.setSrc(file.id);
|
|
314
|
-
if (isSupplement) {
|
|
315
|
-
const tr = this.view.state.tr;
|
|
316
|
-
this.view.state.doc.descendants((node, pos) => {
|
|
317
|
-
if (node.type === node.type.schema.nodes.supplement) {
|
|
318
|
-
const href = node.attrs.href;
|
|
319
|
-
if (href === file.id) {
|
|
320
|
-
tr.delete(pos, pos + node.nodeSize);
|
|
321
|
-
this.view.dispatch(tr);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
if (node.type !== node.type.schema.nodes.supplements &&
|
|
325
|
-
node.type !== node.type.schema.nodes.manuscript) {
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
223
|
if (can.uploadFile) {
|
|
333
|
-
handleUpload = (0,
|
|
224
|
+
handlers.handleUpload = (0, media_1.createFileUploader)(this.upload, 'image/*');
|
|
334
225
|
}
|
|
335
226
|
if (can.detachFile) {
|
|
336
|
-
handleDelete = () => {
|
|
227
|
+
handlers.handleDelete = () => {
|
|
337
228
|
const pos = this.getPos();
|
|
338
229
|
const tr = this.view.state.tr;
|
|
339
230
|
tr.delete(pos, pos + this.node.nodeSize);
|
|
340
231
|
this.view.dispatch(tr);
|
|
341
232
|
};
|
|
342
233
|
}
|
|
343
|
-
this.reactTools
|
|
344
|
-
if (this.
|
|
345
|
-
const componentProps = {
|
|
346
|
-
can,
|
|
347
|
-
getDoc: () => this.view.state.doc,
|
|
348
|
-
getFiles: this.props.getFiles,
|
|
349
|
-
onDownload: handleDownload,
|
|
350
|
-
onUpload: handleUpload,
|
|
351
|
-
onDetach: handleDetach,
|
|
352
|
-
onReplace: handleReplace,
|
|
353
|
-
onDelete: handleDelete,
|
|
354
|
-
hasSiblings: () => {
|
|
355
|
-
return this.countFigures() > 1;
|
|
356
|
-
},
|
|
357
|
-
};
|
|
358
|
-
this.reactTools = (0, ReactSubView_1.default)(this.props, FigureDropdown_1.FigureOptions, componentProps, this.node, this.getPos, this.view);
|
|
234
|
+
this.reactTools = (0, media_1.createReactTools)(this.node, this.view, this.getPos, this.props, handlers, false, () => this.countFigures() > 1);
|
|
235
|
+
if (this.reactTools) {
|
|
359
236
|
this.dom.insertBefore(this.reactTools, this.dom.firstChild);
|
|
360
237
|
}
|
|
361
238
|
}
|
|
@@ -21,7 +21,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
21
21
|
exports.ImageElementView = exports.figurePositions = void 0;
|
|
22
22
|
const style_guide_1 = require("@manuscripts/style-guide");
|
|
23
23
|
const transform_1 = require("@manuscripts/transform");
|
|
24
|
-
const
|
|
24
|
+
const position_menu_1 = require("../lib/position-menu");
|
|
25
25
|
const block_view_1 = __importDefault(require("./block_view"));
|
|
26
26
|
const creators_1 = require("./creators");
|
|
27
27
|
const ReactSubView_1 = __importDefault(require("./ReactSubView"));
|
|
@@ -35,67 +35,43 @@ class ImageElementView extends block_view_1.default {
|
|
|
35
35
|
constructor() {
|
|
36
36
|
super(...arguments);
|
|
37
37
|
this.ignoreMutation = () => true;
|
|
38
|
-
this.
|
|
39
|
-
const can = this.props.getCapabilities();
|
|
40
|
-
this.positionMenuWrapper = document.createElement('div');
|
|
41
|
-
this.positionMenuWrapper.classList.add('position-menu');
|
|
42
|
-
const positionMenuButton = document.createElement('div');
|
|
43
|
-
positionMenuButton.classList.add('position-menu-button');
|
|
38
|
+
this.showPositionMenu = () => {
|
|
44
39
|
const firstFigure = this.getFirstFigure();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
switch (this.figurePosition) {
|
|
48
|
-
case figurePositions.left:
|
|
49
|
-
icon = icons_1.imageLeftIcon;
|
|
50
|
-
break;
|
|
51
|
-
case figurePositions.right:
|
|
52
|
-
icon = icons_1.imageRightIcon;
|
|
53
|
-
break;
|
|
54
|
-
default:
|
|
55
|
-
icon = icons_1.imageDefaultIcon;
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
if (icon) {
|
|
59
|
-
positionMenuButton.innerHTML = icon;
|
|
40
|
+
if (!firstFigure) {
|
|
41
|
+
return;
|
|
60
42
|
}
|
|
61
|
-
if (can.editArticle) {
|
|
62
|
-
positionMenuButton.addEventListener('click', this.showPositionMenu);
|
|
63
|
-
}
|
|
64
|
-
this.positionMenuWrapper.appendChild(positionMenuButton);
|
|
65
|
-
return this.positionMenuWrapper;
|
|
66
|
-
};
|
|
67
|
-
this.showPositionMenu = () => {
|
|
68
43
|
this.props.popper.destroy();
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.updateAllFiguresPosition(figurePositions.left);
|
|
76
|
-
},
|
|
77
|
-
icon: 'ImageLeft',
|
|
78
|
-
selected: this.figurePosition === figurePositions.left,
|
|
44
|
+
const options = [
|
|
45
|
+
{
|
|
46
|
+
label: 'Left',
|
|
47
|
+
action: () => {
|
|
48
|
+
this.props.popper.destroy();
|
|
49
|
+
this.updateAllFiguresPosition(figurePositions.left);
|
|
79
50
|
},
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
51
|
+
icon: 'ImageLeft',
|
|
52
|
+
selected: this.figurePosition === figurePositions.left,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: 'Default',
|
|
56
|
+
action: () => {
|
|
57
|
+
this.props.popper.destroy();
|
|
58
|
+
this.updateAllFiguresPosition(figurePositions.default);
|
|
88
59
|
},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
60
|
+
icon: 'ImageDefault',
|
|
61
|
+
selected: !this.figurePosition,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: 'Right',
|
|
65
|
+
action: () => {
|
|
66
|
+
this.props.popper.destroy();
|
|
67
|
+
this.updateAllFiguresPosition(figurePositions.right);
|
|
97
68
|
},
|
|
98
|
-
|
|
69
|
+
icon: 'ImageRight',
|
|
70
|
+
selected: this.figurePosition === figurePositions.right,
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
const componentProps = {
|
|
74
|
+
actions: options,
|
|
99
75
|
};
|
|
100
76
|
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);
|
|
101
77
|
};
|
|
@@ -128,7 +104,10 @@ class ImageElementView extends block_view_1.default {
|
|
|
128
104
|
if (existingMenu) {
|
|
129
105
|
existingMenu.remove();
|
|
130
106
|
}
|
|
131
|
-
this.
|
|
107
|
+
const firstFigure = this.getFirstFigure();
|
|
108
|
+
this.figurePosition = firstFigure?.attrs.type || figurePositions.default;
|
|
109
|
+
this.positionMenuWrapper = (0, position_menu_1.createPositionMenuWrapper)(this.figurePosition, this.showPositionMenu, this.props);
|
|
110
|
+
this.container.prepend(this.positionMenuWrapper);
|
|
132
111
|
}
|
|
133
112
|
}
|
|
134
113
|
getFirstFigure() {
|