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();
172 this._mediaToInsert
.forEach((media
) => this._insertMediaItem(thumbnailSize
, media
));
174 if (this._mediaToInsertByClipboard
) {
175 Clipboard
.unmark("com.woltlab.wcf.media", Array
.from(this._mediaToInsert
.keys()));
177 this._mediaToInsert
= new Map();
178 this._mediaToInsertByClipboard
= false;
179 // close manager dialog
181 UiDialog
.close(this);
185 * Inserts a single media item into the editor.
187 _insertMediaItem(thumbnailSize
, media
) {
190 ["small", "medium", "large", "original"].some((size
) => {
191 if (media
[size
+ "ThumbnailHeight"] != 0) {
193 if (thumbnailSize
== size
) {
199 thumbnailSize
= available
;
200 if (!thumbnailSize
) {
201 thumbnailSize
= "original";
203 let link
= media
.link
;
204 if (thumbnailSize
!== "original") {
205 link
= media
[thumbnailSize
+ "ThumbnailLink"];
207 this._options
.editor
.insert
.html(`<img src="${link}" class="woltlabSuiteMedia" data-media-id="${media.mediaID}" data-media-size="${thumbnailSize}">`);
210 this._options
.editor
.insert
.text(`[wsm='${media.mediaID}'][/wsm]`);
214 * Is called after media files are successfully uploaded to insert copied media.
216 _mediaUploaded(data
) {
217 if (this._uploadId
!== null && this._upload
=== data
.upload
) {
218 if (this._uploadId
=== data
.uploadId
||
219 (Array
.isArray(this._uploadId
) && this._uploadId
.indexOf(data
.uploadId
) !== -1)) {
220 this._mediaToInsert
= new Map(data
.media
.entries());
221 this._insertMedia(null, "medium", false);
222 this._uploadId
= null;
227 * Handles clicking on the insert button.
229 _openInsertDialog(event
) {
230 const target
= event
.currentTarget
;
231 this.insertMedia([~~target
.dataset
.objectId
]);
234 * Is called to insert the media files with the given ids into an editor.
236 clipboardInsertMedia(mediaIds
) {
237 this.insertMedia(mediaIds
, true);
240 * Prepares insertion of the media files with the given ids.
242 insertMedia(mediaIds
, insertedByClipboard
) {
243 this._mediaToInsert
= new Map();
244 this._mediaToInsertByClipboard
= insertedByClipboard
|| false;
245 // open the insert dialog if all media files are images
246 let imagesOnly
= true;
247 mediaIds
.forEach((mediaId
) => {
248 const media
= this._media
.get(mediaId
);
249 this._mediaToInsert
.set(media
.mediaID
, media
);
250 if (!media
.isImage
) {
255 const thumbnailSizes
= this._getThumbnailSizes();
256 if (thumbnailSizes
.length
) {
257 UiDialog
.close(this);
258 const dialogId
= this._getInsertDialogId();
259 if (UiDialog
.getDialog(dialogId
)) {
260 UiDialog
.openStatic(dialogId
, null);
263 this._buildInsertDialog();
267 this._insertMedia(undefined, "original");
277 setupMediaElement(media
, mediaElement
) {
278 super.setupMediaElement(media
, mediaElement
);
279 // add media insertion icon
280 const buttons
= mediaElement
.querySelector("nav.buttonGroupNavigation > ul");
281 const listItem
= document
.createElement("li");
282 listItem
.className
= "jsMediaInsertButton";
283 listItem
.dataset
.objectId
= media
.mediaID
.toString();
284 buttons
.appendChild(listItem
);
285 listItem
.innerHTML
= `
287 <span class="icon icon16 fa-plus jsTooltip" title="${Language.get("wcf.global.button.insert")}"></span>
288 <span class="invisible">${Language.get("wcf.global.button.insert")}</span>
292 Core
.enableLegacyInheritance(MediaManagerEditor
);
293 return MediaManagerEditor
;