2 * Provides the media manager dialog for selecting media for Redactor editors.
4 * @author Matthias Schmidt
5 * @copyright 2001-2021 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @module WoltLabSuite/Core/Media/Manager/Editor
9 define(["require", "exports", "tslib", "./Base", "../../Core", "../../Event/Handler", "../../Dom/Traverse", "../../Language", "../../Ui/Dialog", "../../Controller/Clipboard", "../../Dom/Util"], function (require
, exports
, tslib_1
, Base_1
, Core
, EventHandler
, DomTraverse
, Language
, UiDialog
, Clipboard
, Util_1
) {
11 Base_1
= tslib_1
.__importDefault(Base_1
);
12 Core
= tslib_1
.__importStar(Core
);
13 EventHandler
= tslib_1
.__importStar(EventHandler
);
14 DomTraverse
= tslib_1
.__importStar(DomTraverse
);
15 Language
= tslib_1
.__importStar(Language
);
16 UiDialog
= tslib_1
.__importStar(UiDialog
);
17 Clipboard
= tslib_1
.__importStar(Clipboard
);
18 Util_1
= tslib_1
.__importDefault(Util_1
);
19 class MediaManagerEditor
extends Base_1
.default {
20 constructor(options
) {
21 options
= Core
.extend({
25 this._forceClipboard
= true;
26 this._activeButton
= null;
27 const context
= this._options
.editor
? this._options
.editor
.core
.toolbar()[0] : undefined;
28 this._buttons
= (context
|| window
.document
).getElementsByClassName(this._options
.buttonClass
|| "jsMediaEditorButton");
29 Array
.from(this._buttons
).forEach((button
) => {
30 button
.addEventListener("click", (ev
) => this._click(ev
));
32 this._mediaToInsert
= new Map();
33 this._mediaToInsertByClipboard
= false;
34 this._uploadData
= null;
35 this._uploadId
= null;
36 if (this._options
.editor
&& !this._options
.editor
.opts
.woltlab
.attachments
) {
37 const editorId
= this._options
.editor
.$editor
[0].dataset
.elementId
;
38 const uuid1
= EventHandler
.add("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, (data
) => this._editorUpload(data
));
39 const uuid2
= EventHandler
.add("com.woltlab.wcf.redactor2", `pasteFromClipboard_${editorId}`, (data
) => this._editorUpload(data
));
40 EventHandler
.add("com.woltlab.wcf.redactor2", `destroy_${editorId}`, () => {
41 EventHandler
.remove("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, uuid1
);
42 EventHandler
.remove("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, uuid2
);
44 EventHandler
.add("com.woltlab.wcf.media.upload", "success", (data
) => this._mediaUploaded(data
));
47 _addButtonEventListeners() {
48 super._addButtonEventListeners();
49 if (!this._mediaManagerMediaList
) {
52 DomTraverse
.childrenByTag(this._mediaManagerMediaList
, "LI").forEach((listItem
) => {
53 const insertIcon
= listItem
.querySelector(".jsMediaInsertButton");
55 insertIcon
.classList
.remove("jsMediaInsertButton");
56 insertIcon
.addEventListener("click", (ev
) => this._openInsertDialog(ev
));
61 * Builds the dialog to setup inserting media files.
63 _buildInsertDialog() {
64 let thumbnailOptions
= "";
65 this._getThumbnailSizes().forEach((thumbnailSize
) => {
70 Language
.get("wcf.media.insert.imageSize." + thumbnailSize
) +
73 thumbnailOptions
+= '<option value="original">' + Language
.get("wcf.media.insert.imageSize.original") + "</option>";
76 <dl class="thumbnailSizeSelection">
77 <dt>${Language.get("wcf.media.insert.imageSize")}</dt>
79 <select name="thumbnailSize">
85 <div class="formSubmit">
86 <button class="buttonPrimary">${Language.get("wcf.global.button.insert")}</button>
91 id
: this._getInsertDialogId(),
93 onClose
: () => this._editorClose(),
94 onSetup
: (content
) => {
95 content
.querySelector(".buttonPrimary").addEventListener("click", (ev
) => this._insertMedia(ev
));
96 Util_1
.default.show(content
.querySelector(".thumbnailSizeSelection"));
98 title
: Language
.get("wcf.media.insert"),
106 this._activeButton
= event
.currentTarget
;
111 // check if data needs to be uploaded
112 if (this._uploadData
) {
113 const fileUploadData
= this._uploadData
;
114 if (fileUploadData
.file
) {
115 this._upload
.uploadFile(fileUploadData
.file
);
118 const blobUploadData
= this._uploadData
;
119 this._uploadId
= this._upload
.uploadBlob(blobUploadData
.blob
);
121 this._uploadData
= null;
125 * Handles pasting and dragging and dropping files into the editor.
127 _editorUpload(data
) {
128 this._uploadData
= data
;
132 * Returns the id of the insert dialog based on the media files to be inserted.
134 _getInsertDialogId() {
135 return ["mediaInsert", ...this._mediaToInsert
.keys()].join("-");
138 * Returns the supported thumbnail sizes (excluding `original`) for all media images to be inserted.
140 _getThumbnailSizes() {
141 return ["small", "medium", "large"]
143 const sizeSupported
= Array
.from(this._mediaToInsert
.values()).every((media
) => {
144 return media
[size
+ "ThumbnailType"] !== null;
151 .filter((s
) => s
!== null);
154 * Inserts media files into the editor.
156 _insertMedia(event
, thumbnailSize
, closeEditor
= false) {
157 if (closeEditor
=== undefined)
159 // update insert options with selected values if method is called by clicking on 'insert' button
162 UiDialog
.close(this._getInsertDialogId());
163 const dialogContent
= event
.currentTarget
.closest(".dialogContent");
164 const thumbnailSizeSelect
= dialogContent
.querySelector("select[name=thumbnailSize]");
165 thumbnailSize
= thumbnailSizeSelect
.value
;
167 if (this._options
.callbackInsert
!== null) {
168 this._options
.callbackInsert(this._mediaToInsert
, "separate" /* Separate */, thumbnailSize
);
171 this._options
.editor
.buffer
.set();
173 if (this._mediaToInsertByClipboard
) {
174 Clipboard
.unmark("com.woltlab.wcf.media", Array
.from(this._mediaToInsert
.keys()));
176 this._mediaToInsert
= new Map();
177 this._mediaToInsertByClipboard
= false;
178 // close manager dialog
180 UiDialog
.close(this);
184 * Inserts a single media item into the editor.
186 _insertMediaItem(thumbnailSize
, media
) {
189 ["small", "medium", "large", "original"].some((size
) => {
190 if (media
[size
+ "ThumbnailHeight"] != 0) {
192 if (thumbnailSize
== size
) {
198 thumbnailSize
= available
;
199 if (!thumbnailSize
) {
200 thumbnailSize
= "original";
202 let link
= media
.link
;
203 if (thumbnailSize
!== "original") {
204 link
= media
[thumbnailSize
+ "ThumbnailLink"];
206 this._options
.editor
.insert
.html(`<img src="${link}" class="woltlabSuiteMedia" data-media-id="${media.mediaID}" data-media-size="${thumbnailSize}">`);
209 this._options
.editor
.insert
.text(`[wsm='${media.mediaID}'][/wsm]`);
213 * Is called after media files are successfully uploaded to insert copied media.
215 _mediaUploaded(data
) {
216 if (this._uploadId
!== null && this._upload
=== data
.upload
) {
217 if (this._uploadId
=== data
.uploadId
||
218 (Array
.isArray(this._uploadId
) && this._uploadId
.indexOf(data
.uploadId
) !== -1)) {
219 this._mediaToInsert
= new Map(data
.media
.entries());
220 this._insertMedia(null, "medium", false);
221 this._uploadId
= null;
226 * Handles clicking on the insert button.
228 _openInsertDialog(event
) {
229 const target
= event
.currentTarget
;
230 this.insertMedia([~~target
.dataset
.objectId
]);
233 * Is called to insert the media files with the given ids into an editor.
235 clipboardInsertMedia(mediaIds
) {
236 this.insertMedia(mediaIds
, true);
239 * Prepares insertion of the media files with the given ids.
241 insertMedia(mediaIds
, insertedByClipboard
) {
242 this._mediaToInsert
= new Map();
243 this._mediaToInsertByClipboard
= insertedByClipboard
|| false;
244 // open the insert dialog if all media files are images
245 let imagesOnly
= true;
246 mediaIds
.forEach((mediaId
) => {
247 const media
= this._media
.get(mediaId
);
248 this._mediaToInsert
.set(media
.mediaID
, media
);
249 if (!media
.isImage
) {
254 const thumbnailSizes
= this._getThumbnailSizes();
255 if (thumbnailSizes
.length
) {
256 UiDialog
.close(this);
257 const dialogId
= this._getInsertDialogId();
258 if (UiDialog
.getDialog(dialogId
)) {
259 UiDialog
.openStatic(dialogId
, null);
262 this._buildInsertDialog();
266 this._insertMedia(undefined, "original");
276 setupMediaElement(media
, mediaElement
) {
277 super.setupMediaElement(media
, mediaElement
);
278 // add media insertion icon
279 const buttons
= mediaElement
.querySelector("nav.buttonGroupNavigation > ul");
280 const listItem
= document
.createElement("li");
281 listItem
.className
= "jsMediaInsertButton";
282 listItem
.dataset
.objectId
= media
.mediaID
.toString();
283 buttons
.appendChild(listItem
);
284 listItem
.innerHTML
= `
286 <span class="icon icon16 fa-plus jsTooltip" title="${Language.get("wcf.global.button.insert")}"></span>
287 <span class="invisible">${Language.get("wcf.global.button.insert")}</span>
291 Core
.enableLegacyInheritance(MediaManagerEditor
);
292 return MediaManagerEditor
;