--- /dev/null
- Clipboard.setup({
- hasMarkedItems: hasMarkedItems,
- pageClassName: pageClassName,
- });
+/**
+ * Initializes modules required for media clipboard.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Clipboard
+ * @woltlabExcludeBundle tiny
+ */
+
+import MediaManager from "./Manager/Base";
+import MediaManagerEditor from "./Manager/Editor";
+import * as Clipboard from "../Controller/Clipboard";
+import * as UiNotification from "../Ui/Notification";
+import * as UiDialog from "../Ui/Dialog";
+import * as EventHandler from "../Event/Handler";
+import * as Language from "../Language";
+import * as Ajax from "../Ajax";
+import { AjaxCallbackObject, AjaxCallbackSetup } from "../Ajax/Data";
+import { DialogCallbackObject, DialogCallbackSetup } from "../Ui/Dialog/Data";
+
+let _mediaManager: MediaManager;
++const _didInit = false;
+
+class MediaClipboard implements AjaxCallbackObject, DialogCallbackObject {
+ public _ajaxSetup(): ReturnType<AjaxCallbackSetup> {
+ return {
+ data: {
+ className: "wcf\\data\\media\\MediaAction",
+ },
+ };
+ }
+
+ public _ajaxSuccess(data): void {
+ switch (data.actionName) {
+ case "getSetCategoryDialog":
+ UiDialog.open(this, data.returnValues.template);
+
+ break;
+
+ case "setCategory":
+ UiDialog.close(this);
+
+ UiNotification.show();
+
+ Clipboard.reload();
+
+ break;
+ }
+ }
+
+ public _dialogSetup(): ReturnType<DialogCallbackSetup> {
+ return {
+ id: "mediaSetCategoryDialog",
+ options: {
+ onSetup: (content) => {
+ content.querySelector("button")!.addEventListener("click", (event) => {
+ event.preventDefault();
+
+ const category = content.querySelector('select[name="categoryID"]') as HTMLSelectElement;
+ setCategory(~~category.value);
+
+ const target = event.currentTarget as HTMLButtonElement;
+ target.disabled = true;
+ });
+ },
+ title: Language.get("wcf.media.setCategory"),
+ },
+ source: null,
+ };
+ }
+}
+
+const ajax = new MediaClipboard();
+
+let clipboardObjectIds: number[] = [];
+
+interface ClipboardActionData {
+ data: {
+ actionName: "com.woltlab.wcf.media.delete" | "com.woltlab.wcf.media.insert" | "com.woltlab.wcf.media.setCategory";
+ parameters: {
+ objectIDs: number[];
+ };
+ };
+ responseData: null;
+}
+
+/**
+ * Handles successful clipboard actions.
+ */
+function clipboardAction(actionData: ClipboardActionData): void {
+ const mediaIds = actionData.data.parameters.objectIDs;
+
+ switch (actionData.data.actionName) {
+ case "com.woltlab.wcf.media.delete":
+ // only consider events if the action has been executed
+ if (actionData.responseData !== null) {
+ _mediaManager.clipboardDeleteMedia(mediaIds);
+ }
+
+ break;
+
+ case "com.woltlab.wcf.media.insert": {
+ const mediaManagerEditor = _mediaManager as MediaManagerEditor;
+ mediaManagerEditor.clipboardInsertMedia(mediaIds);
+
+ break;
+ }
+
+ case "com.woltlab.wcf.media.setCategory":
+ clipboardObjectIds = mediaIds;
+
+ Ajax.api(ajax, {
+ actionName: "getSetCategoryDialog",
+ });
+
+ break;
+ }
+}
+
+/**
+ * Sets the category of the marked media files.
+ */
+function setCategory(categoryID: number) {
+ Ajax.api(ajax, {
+ actionName: "setCategory",
+ objectIDs: clipboardObjectIds,
+ parameters: {
+ categoryID: categoryID,
+ },
+ });
+}
+
+export function init(pageClassName: string, hasMarkedItems: boolean, mediaManager: MediaManager): void {
- EventHandler.add("com.woltlab.wcf.clipboard", "com.woltlab.wcf.media", (data) => clipboardAction(data));
++ if (!_didInit) {
++ Clipboard.setup({
++ hasMarkedItems: hasMarkedItems,
++ pageClassName: pageClassName,
++ });
+
++ EventHandler.add("com.woltlab.wcf.clipboard", "com.woltlab.wcf.media", (data) => clipboardAction(data));
++ }
++
+ _mediaManager = mediaManager;
++}
+
++export function setMediaManager(mediaManager: MediaManager): void {
++ _mediaManager = mediaManager;
+}
--- /dev/null
- protected readonly _id;
+/**
+ * Provides the media manager dialog.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Manager/Base
+ * @woltlabExcludeBundle tiny
+ */
+
+import * as Core from "../../Core";
+import { Media, MediaManagerOptions, MediaEditorCallbackObject, MediaUploadSuccessEventData } from "../Data";
+import * as Language from "../../Language";
+import * as Permission from "../../Permission";
+import * as DomChangeListener from "../../Dom/Change/Listener";
+import * as EventHandler from "../../Event/Handler";
+import * as DomTraverse from "../../Dom/Traverse";
+import * as DomUtil from "../../Dom/Util";
+import * as UiDialog from "../../Ui/Dialog";
+import { DialogCallbackSetup, DialogCallbackObject } from "../../Ui/Dialog/Data";
+import * as Clipboard from "../../Controller/Clipboard";
+import UiPagination from "../../Ui/Pagination";
+import * as UiNotification from "../../Ui/Notification";
+import * as StringUtil from "../../StringUtil";
+import MediaManagerSearch from "./Search";
+import MediaUpload from "../Upload";
+import MediaEditor from "../Editor";
+import * as MediaClipboard from "../Clipboard";
+import { ObjectActionData } from "../../Ui/Object/Data";
+
+let mediaManagerCounter = 0;
+
+interface DialogInitAjaxResponseData {
+ returnValues: {
+ hasMarkedItems: number;
+ media: object;
+ pageCount: number;
+ };
+}
+
+interface SetMediaAdditionalData {
+ pageCount: number;
+ pageNo: number;
+}
+
+abstract class MediaManager<TOptions extends MediaManagerOptions = MediaManagerOptions>
+ implements DialogCallbackObject, MediaEditorCallbackObject {
+ protected _forceClipboard = false;
+ protected _hadInitiallyMarkedItems = false;
++ protected readonly _id: string;
+ protected readonly _listItems = new Map<number, HTMLLIElement>();
+ protected _media = new Map<number, Media>();
+ protected _mediaCategorySelect: HTMLSelectElement | null;
+ protected readonly _mediaEditor: MediaEditor | null = null;
+ protected _mediaManagerMediaList: HTMLElement | null = null;
+ protected _pagination: UiPagination | null = null;
+ protected _search: MediaManagerSearch | null = null;
+ protected _upload: any = null;
+ protected readonly _options: TOptions;
+
+ constructor(options: Partial<TOptions>) {
+ this._options = Core.extend(
+ {
+ dialogTitle: Language.get("wcf.media.manager"),
+ imagesOnly: false,
+ minSearchLength: 3,
+ },
+ options,
+ ) as TOptions;
+
+ this._id = `mediaManager${mediaManagerCounter++}`;
+
+ if (Permission.get("admin.content.cms.canManageMedia")) {
+ this._mediaEditor = new MediaEditor(this);
+ }
+
+ DomChangeListener.add("WoltLabSuite/Core/Media/Manager", () => this._addButtonEventListeners());
+
+ EventHandler.add("com.woltlab.wcf.media.upload", "success", (data: MediaUploadSuccessEventData) =>
+ this._openEditorAfterUpload(data),
+ );
+ }
+
+ /**
+ * Adds click event listeners to media buttons.
+ */
+ protected _addButtonEventListeners(): void {
+ if (!this._mediaManagerMediaList || !Permission.get("admin.content.cms.canManageMedia")) return;
+
+ DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => {
+ const editIcon = listItem.querySelector(".jsMediaEditButton");
+ if (editIcon) {
+ editIcon.classList.remove("jsMediaEditButton");
+ editIcon.addEventListener("click", (ev) => this._editMedia(ev));
+ }
+ });
+ }
+
+ /**
+ * Is called when a new category is selected.
+ */
+ protected _categoryChange(): void {
+ this._search!.search();
+ }
+
+ /**
+ * Handles clicks on the media manager button.
+ */
+ protected _click(event: Event): void {
+ event.preventDefault();
+
+ UiDialog.open(this);
+ }
+
+ /**
+ * Is called if the media manager dialog is closed.
+ */
+ protected _dialogClose(): void {
+ // only show media clipboard if editor is open
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ Clipboard.hideEditor("com.woltlab.wcf.media");
+ }
+ }
+
+ /**
+ * Initializes the dialog when first loaded.
+ */
+ protected _dialogInit(content: HTMLElement, data: DialogInitAjaxResponseData): void {
+ // store media data locally
+ Object.entries(data.returnValues.media || {}).forEach(([mediaId, media]) => {
+ this._media.set(~~mediaId, media);
+ });
+
+ this._initPagination(~~data.returnValues.pageCount);
+
+ this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems > 0;
+ }
+
+ /**
+ * Returns all data to setup the media manager dialog.
+ */
+ public _dialogSetup(): ReturnType<DialogCallbackSetup> {
+ return {
+ id: this._id,
+ options: {
+ onClose: () => this._dialogClose(),
+ onShow: () => this._dialogShow(),
+ title: this._options.dialogTitle,
+ },
+ source: {
+ after: (content: HTMLElement, data: DialogInitAjaxResponseData) => this._dialogInit(content, data),
+ data: {
+ actionName: "getManagementDialog",
+ className: "wcf\\data\\media\\MediaAction",
+ parameters: {
+ mode: this.getMode(),
+ imagesOnly: this._options.imagesOnly,
+ },
+ },
+ },
+ };
+ }
+
+ /**
+ * Is called if the media manager dialog is shown.
+ */
+ protected _dialogShow(): void {
+ if (!this._mediaManagerMediaList) {
+ const dialog = this.getDialog();
+
+ this._mediaManagerMediaList = dialog.querySelector(".mediaManagerMediaList");
+
+ this._mediaCategorySelect = dialog.querySelector(".mediaManagerCategoryList > select");
+ if (this._mediaCategorySelect) {
+ this._mediaCategorySelect.addEventListener("change", () => this._categoryChange());
+ }
+
+ // store list items locally
+ const listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList!, "LI");
+ listItems.forEach((listItem: HTMLLIElement) => {
+ this._listItems.set(~~listItem.dataset.objectId!, listItem);
+ });
+
+ if (Permission.get("admin.content.cms.canManageMedia")) {
+ const uploadButton = UiDialog.getDialog(this)!.dialog.querySelector(".mediaManagerMediaUploadButton")!;
+ this._upload = new MediaUpload(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList!), {
+ mediaManager: this,
+ });
+
+ EventHandler.add("WoltLabSuite/Core/Ui/Object/Action", "delete", (data: ObjectActionData) =>
+ this.removeMedia(~~data.objectElement.dataset.objectId!),
+ );
+ }
+
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ MediaClipboard.init("menuManagerDialog-" + this.getMode(), this._hadInitiallyMarkedItems ? true : false, this);
+ } else {
+ this._removeClipboardCheckboxes();
+ }
+
+ this._search = new MediaManagerSearch(this);
+
+ if (!listItems.length) {
+ this._search.hideSearch();
+ }
++ } else {
++ MediaClipboard.setMediaManager(this);
+ }
+
+ // only show media clipboard if editor is open
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ Clipboard.showEditor();
+ }
+ }
+
+ /**
+ * Opens the media editor for a media file.
+ */
+ protected _editMedia(event: Event): void {
+ if (!Permission.get("admin.content.cms.canManageMedia")) {
+ throw new Error("You are not allowed to edit media files.");
+ }
+
+ UiDialog.close(this);
+
+ const target = event.currentTarget as HTMLElement;
+
+ this._mediaEditor!.edit(this._media.get(~~target.dataset.objectId!)!);
+ }
+
+ /**
+ * Re-opens the manager dialog after closing the editor dialog.
+ */
+ _editorClose(): void {
+ UiDialog.open(this);
+ }
+
+ /**
+ * Re-opens the manager dialog and updates the media data after successfully editing a media file.
+ */
+ _editorSuccess(media: Media, oldCategoryId?: number, closedEditorDialog = true): void {
+ // if the category changed of media changed and category
+ // is selected, check if media list needs to be refreshed
+ if (this._mediaCategorySelect) {
+ const selectedCategoryId = ~~this._mediaCategorySelect.value;
+
+ if (selectedCategoryId) {
+ const newCategoryId = ~~media.categoryID;
+
+ if (
+ oldCategoryId != newCategoryId &&
+ (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId)
+ ) {
+ this._search!.search();
+ }
+ }
+ }
+
+ if (closedEditorDialog) {
+ UiDialog.open(this);
+ }
+
+ this._media.set(~~media.mediaID, media);
+
+ const listItem = this._listItems.get(~~media.mediaID)!;
+ const p = listItem.querySelector(".mediaTitle")!;
+ if (media.isMultilingual) {
+ if (media.title && media.title[window.LANGUAGE_ID]) {
+ p.textContent = media.title[window.LANGUAGE_ID];
+ } else {
+ p.textContent = media.filename;
+ }
+ } else {
+ if (media.title && media.title[media.languageID!]) {
+ p.textContent = media.title[media.languageID!];
+ } else {
+ p.textContent = media.filename;
+ }
+ }
+
+ const thumbnail = listItem.querySelector(".mediaThumbnail")!;
+ thumbnail.innerHTML = media.elementTag;
+ // Bust browser cache by adding additional parameter.
+ const img = thumbnail.querySelector("img");
+ if (img) {
+ img.src += `&refresh=${Date.now()}`;
+ }
+ }
+
+ /**
+ * Initializes the dialog pagination.
+ */
+ protected _initPagination(pageCount: number, pageNo?: number): void {
+ if (pageNo === undefined) pageNo = 1;
+
+ if (pageCount > 1) {
+ const newPagination = document.createElement("div");
+ newPagination.className = "paginationBottom jsPagination";
+ DomUtil.replaceElement(
+ UiDialog.getDialog(this)!.content.querySelector(".jsPagination") as HTMLElement,
+ newPagination,
+ );
+
+ this._pagination = new UiPagination(newPagination, {
+ activePage: pageNo,
+ callbackSwitch: (pageNo: number) => this._search!.search(pageNo),
+ maxPage: pageCount,
+ });
+ } else if (this._pagination) {
+ DomUtil.hide(this._pagination.getElement());
+ }
+ }
+
+ /**
+ * Removes all media clipboard checkboxes.
+ */
+ _removeClipboardCheckboxes(): void {
+ this._mediaManagerMediaList!.querySelectorAll(".mediaCheckbox").forEach((el) => el.remove());
+ }
+
+ /**
+ * Opens the media editor after uploading a single file.
+ *
+ * @since 5.2
+ */
+ _openEditorAfterUpload(data: MediaUploadSuccessEventData): void {
+ if (data.upload === this._upload && !data.isMultiFileUpload && !this._upload.hasPendingUploads()) {
+ const keys = Object.keys(data.media);
+
+ if (keys.length) {
+ UiDialog.close(this);
+
+ this._mediaEditor!.edit(this._media.get(~~data.media[keys[0]].mediaID)!);
+ }
+ }
+ }
+
+ /**
+ * Sets the displayed media (after a search).
+ */
+ _setMedia(media: object): void {
+ this._media = new Map<number, Media>(Object.entries(media).map(([mediaId, media]) => [~~mediaId, media]));
+
+ let info = DomTraverse.nextByClass(this._mediaManagerMediaList!, "info") as HTMLElement;
+
+ if (this._media.size) {
+ if (info) {
+ DomUtil.hide(info);
+ }
+ } else {
+ if (info === null) {
+ info = document.createElement("p");
+ info.className = "info";
+ info.textContent = Language.get("wcf.media.search.noResults");
+ }
+
+ DomUtil.show(info);
+ DomUtil.insertAfter(info, this._mediaManagerMediaList!);
+ }
+
+ DomTraverse.childrenByTag(this._mediaManagerMediaList!, "LI").forEach((listItem) => {
+ if (!this._media.has(~~listItem.dataset.objectId!)) {
+ DomUtil.hide(listItem);
+ } else {
+ DomUtil.show(listItem);
+ }
+ });
+
+ DomChangeListener.trigger();
+
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ Clipboard.reload();
+ } else {
+ this._removeClipboardCheckboxes();
+ }
+ }
+
+ /**
+ * Adds a media file to the manager.
+ */
+ public addMedia(media: Media, listItem: HTMLLIElement): void {
+ if (!media.languageID) media.isMultilingual = 1;
+
+ this._media.set(~~media.mediaID, media);
+ this._listItems.set(~~media.mediaID, listItem);
+
+ if (this._listItems.size === 1) {
+ this._search!.showSearch();
+ }
+ }
+
+ /**
+ * Is called after the media files with the given ids have been deleted via clipboard.
+ */
+ public clipboardDeleteMedia(mediaIds: number[]): void {
+ mediaIds.forEach((mediaId) => {
+ this.removeMedia(~~mediaId);
+ });
+
+ UiNotification.show();
+ }
+
+ /**
+ * Returns the id of the currently selected category or `0` if no category is selected.
+ */
+ public getCategoryId(): number {
+ if (this._mediaCategorySelect) {
+ return ~~this._mediaCategorySelect.value;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Returns the media manager dialog element.
+ */
+ getDialog(): HTMLElement {
+ return UiDialog.getDialog(this)!.dialog;
+ }
+
+ /**
+ * Returns the mode of the media manager.
+ */
+ public getMode(): string {
+ return "";
+ }
+
+ /**
+ * Returns the media manager option with the given name.
+ */
+ public getOption(name: string): any {
+ if (this._options[name]) {
+ return this._options[name];
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes a media file.
+ */
+ public removeMedia(mediaId: number): void {
+ if (this._listItems.has(mediaId)) {
+ // remove list item
+ try {
+ this._listItems.get(mediaId)!.remove();
+ } catch (e) {
+ // ignore errors if item has already been removed by other code
+ }
+
+ this._listItems.delete(mediaId);
+ this._media.delete(mediaId);
+ }
+ }
+
+ /**
+ * Changes the displayed media to the previously displayed media.
+ */
+ public resetMedia(): void {
+ // calling WoltLabSuite/Core/Media/Manager/Search.search() reloads the first page of the dialog
+ this._search!.search();
+ }
+
+ /**
+ * Sets the media files currently displayed.
+ */
+ setMedia(media: object, template: string, additionalData: SetMediaAdditionalData): void {
+ const hasMedia = Object.entries(media).length > 0;
+
+ if (hasMedia) {
+ const ul = document.createElement("ul");
+ ul.innerHTML = template;
+
+ DomTraverse.childrenByTag(ul, "LI").forEach((listItem) => {
+ if (!this._listItems.has(~~listItem.dataset.objectId!)) {
+ this._listItems.set(~~listItem.dataset.objectId!, listItem);
+
+ this._mediaManagerMediaList!.appendChild(listItem);
+ }
+ });
+ }
+
+ this._initPagination(additionalData.pageCount, additionalData.pageNo);
+
+ this._setMedia(media);
+ }
+
+ /**
+ * Sets up a new media element.
+ */
+ public setupMediaElement(media: Media, mediaElement: HTMLElement): void {
+ const mediaInformation = DomTraverse.childByClass(mediaElement, "mediaInformation")!;
+
+ const buttonGroupNavigation = document.createElement("nav");
+ buttonGroupNavigation.className = "jsMobileNavigation buttonGroupNavigation";
+ mediaInformation.parentNode!.appendChild(buttonGroupNavigation);
+
+ const buttons = document.createElement("ul");
+ buttons.className = "buttonList iconList";
+ buttonGroupNavigation.appendChild(buttons);
+
+ const listItem = document.createElement("li");
+ listItem.className = "mediaCheckbox";
+ buttons.appendChild(listItem);
+
+ const a = document.createElement("a");
+ listItem.appendChild(a);
+
+ const label = document.createElement("label");
+ a.appendChild(label);
+
+ const checkbox = document.createElement("input");
+ checkbox.className = "jsClipboardItem";
+ checkbox.type = "checkbox";
+ checkbox.dataset.objectId = media.mediaID.toString();
+ label.appendChild(checkbox);
+
+ if (Permission.get("admin.content.cms.canManageMedia")) {
+ const editButton = document.createElement("li");
+ editButton.className = "jsMediaEditButton";
+ editButton.dataset.objectId = media.mediaID.toString();
+ buttons.appendChild(editButton);
+
+ editButton.innerHTML = `
+ <a>
+ <span class="icon icon16 fa-pencil jsTooltip" title="${Language.get("wcf.global.button.edit")}"></span>
+ <span class="invisible">${Language.get("wcf.global.button.edit")}</span>
+ </a>`;
+
+ const deleteButton = document.createElement("li");
+ deleteButton.classList.add("jsObjectAction");
+ deleteButton.dataset.objectAction = "delete";
+
+ // use temporary title to not unescape html in filename
+ const uuid = Core.getUuid();
+ deleteButton.dataset.confirmMessage = StringUtil.unescapeHTML(
+ Language.get("wcf.media.delete.confirmMessage", {
+ title: uuid,
+ }),
+ ).replace(uuid, StringUtil.escapeHTML(media.filename));
+ buttons.appendChild(deleteButton);
+
+ deleteButton.innerHTML = `
+ <a>
+ <span class="icon icon16 fa-times jsTooltip" title="${Language.get("wcf.global.button.delete")}"></span>
+ <span class="invisible">${Language.get("wcf.global.button.delete")}</span>
+ </a>`;
+ }
+ }
+}
+
+Core.enableLegacyInheritance(MediaManager);
+
+export = MediaManager;
--- /dev/null
- return ["mediaInsert", ...this._mediaToInsert.keys()].join("-");
+/**
+ * Provides the media manager dialog for selecting media for Redactor editors.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Manager/Editor
+ * @woltlabExcludeBundle tiny
+ */
+
+import MediaManager from "./Base";
+import * as Core from "../../Core";
+import { Media, MediaInsertType, MediaManagerEditorOptions, MediaUploadSuccessEventData } from "../Data";
+import * as EventHandler from "../../Event/Handler";
+import * as DomTraverse from "../../Dom/Traverse";
+import * as Language from "../../Language";
+import * as UiDialog from "../../Ui/Dialog";
+import * as Clipboard from "../../Controller/Clipboard";
+import { OnDropPayload } from "../../Ui/Redactor/DragAndDrop";
+import DomUtil from "../../Dom/Util";
+
+interface PasteFromClipboard {
+ blob: Blob;
+}
+
+class MediaManagerEditor extends MediaManager<MediaManagerEditorOptions> {
+ protected _activeButton;
+ protected readonly _buttons: HTMLCollectionOf<HTMLElement>;
+ protected _mediaToInsert: Map<number, Media>;
+ protected _mediaToInsertByClipboard: boolean;
+ protected _uploadData: OnDropPayload | PasteFromClipboard | null;
+ protected _uploadId: number | null;
+
+ constructor(options: Partial<MediaManagerEditorOptions>) {
+ options = Core.extend(
+ {
+ callbackInsert: null,
+ },
+ options,
+ );
+
+ super(options);
+
+ this._forceClipboard = true;
+ this._activeButton = null;
+ const context = this._options.editor ? this._options.editor.core.toolbar()[0] : undefined;
+ this._buttons = (context || window.document).getElementsByClassName(
+ this._options.buttonClass || "jsMediaEditorButton",
+ ) as HTMLCollectionOf<HTMLElement>;
+ Array.from(this._buttons).forEach((button) => {
+ button.addEventListener("click", (ev) => this._click(ev));
+ });
+ this._mediaToInsert = new Map<number, Media>();
+ this._mediaToInsertByClipboard = false;
+ this._uploadData = null;
+ this._uploadId = null;
+
+ if (this._options.editor && !this._options.editor.opts.woltlab.attachments) {
+ const editorId = this._options.editor.$editor[0].dataset.elementId as string;
+
+ const uuid1 = EventHandler.add("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, (data: OnDropPayload) =>
+ this._editorUpload(data),
+ );
+ const uuid2 = EventHandler.add(
+ "com.woltlab.wcf.redactor2",
+ `pasteFromClipboard_${editorId}`,
+ (data: OnDropPayload) => this._editorUpload(data),
+ );
+
+ EventHandler.add("com.woltlab.wcf.redactor2", `destroy_${editorId}`, () => {
+ EventHandler.remove("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, uuid1);
+ EventHandler.remove("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, uuid2);
+ });
+
+ EventHandler.add("com.woltlab.wcf.media.upload", "success", (data) => this._mediaUploaded(data));
+ }
+ }
+
+ protected _addButtonEventListeners(): void {
+ super._addButtonEventListeners();
+
+ if (!this._mediaManagerMediaList) {
+ return;
+ }
+
+ DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => {
+ const insertIcon = listItem.querySelector(".jsMediaInsertButton");
+ if (insertIcon) {
+ insertIcon.classList.remove("jsMediaInsertButton");
+ insertIcon.addEventListener("click", (ev) => this._openInsertDialog(ev));
+ }
+ });
+ }
+
+ /**
+ * Builds the dialog to setup inserting media files.
+ */
+ protected _buildInsertDialog(): void {
+ let thumbnailOptions = "";
+
+ this._getThumbnailSizes().forEach((thumbnailSize) => {
+ thumbnailOptions +=
+ '<option value="' +
+ thumbnailSize +
+ '">' +
+ Language.get("wcf.media.insert.imageSize." + thumbnailSize) +
+ "</option>";
+ });
+ thumbnailOptions += '<option value="original">' + Language.get("wcf.media.insert.imageSize.original") + "</option>";
+
+ const dialog = `
+ <div class="section">
+ <dl class="thumbnailSizeSelection">
+ <dt>${Language.get("wcf.media.insert.imageSize")}</dt>
+ <dd>
+ <select name="thumbnailSize">
+ ${thumbnailOptions}
+ </select>
+ </dd>
+ </dl>
+ </div>
+ <div class="formSubmit">
+ <button class="buttonPrimary">${Language.get("wcf.global.button.insert")}</button>
+ </div>`;
+
+ UiDialog.open({
+ _dialogSetup: () => {
+ return {
+ id: this._getInsertDialogId(),
+ options: {
+ onClose: () => this._editorClose(),
+ onSetup: (content) => {
+ content.querySelector(".buttonPrimary")!.addEventListener("click", (ev) => this._insertMedia(ev));
+
+ DomUtil.show(content.querySelector(".thumbnailSizeSelection") as HTMLElement);
+ },
+ title: Language.get("wcf.media.insert"),
+ },
+ source: dialog,
+ };
+ },
+ });
+ }
+
+ protected _click(event: Event): void {
+ this._activeButton = event.currentTarget;
+
+ super._click(event);
+ }
+
+ protected _dialogShow(): void {
+ super._dialogShow();
+
+ // check if data needs to be uploaded
+ if (this._uploadData) {
+ const fileUploadData = this._uploadData as OnDropPayload;
+ if (fileUploadData.file) {
+ this._upload.uploadFile(fileUploadData.file);
+ } else {
+ const blobUploadData = this._uploadData as PasteFromClipboard;
+ this._uploadId = this._upload.uploadBlob(blobUploadData.blob);
+ }
+
+ this._uploadData = null;
+ }
+ }
+
+ /**
+ * Handles pasting and dragging and dropping files into the editor.
+ */
+ protected _editorUpload(data: OnDropPayload): void {
+ this._uploadData = data;
+
+ UiDialog.open(this);
+ }
+
+ /**
+ * Returns the id of the insert dialog based on the media files to be inserted.
+ */
+ protected _getInsertDialogId(): string {
++ return [this._id + "Insert", ...this._mediaToInsert.keys()].join("-");
+ }
+
+ /**
+ * Returns the supported thumbnail sizes (excluding `original`) for all media images to be inserted.
+ */
+ protected _getThumbnailSizes(): string[] {
+ return ["small", "medium", "large"]
+ .map((size) => {
+ const sizeSupported = Array.from(this._mediaToInsert.values()).every((media) => {
+ return media[size + "ThumbnailType"] !== null;
+ });
+
+ if (sizeSupported) {
+ return size;
+ }
+
+ return null;
+ })
+ .filter((s) => s !== null) as string[];
+ }
+
+ /**
+ * Inserts media files into the editor.
+ */
+ protected _insertMedia(event?: Event | null, thumbnailSize?: string, closeEditor = false): void {
+ if (closeEditor === undefined) closeEditor = true;
+
+ // update insert options with selected values if method is called by clicking on 'insert' button
+ // in dialog
+ if (event) {
+ UiDialog.close(this._getInsertDialogId());
+
+ const dialogContent = (event.currentTarget as HTMLElement).closest(".dialogContent")!;
+ const thumbnailSizeSelect = dialogContent.querySelector("select[name=thumbnailSize]") as HTMLSelectElement;
+ thumbnailSize = thumbnailSizeSelect.value;
+ }
+
+ if (this._options.callbackInsert !== null) {
+ this._options.callbackInsert(this._mediaToInsert, MediaInsertType.Separate, thumbnailSize);
+ } else {
+ this._options.editor!.buffer.set();
+
+ this._mediaToInsert.forEach((media) => this._insertMediaItem(thumbnailSize, media));
+ }
+
+ if (this._mediaToInsertByClipboard) {
+ Clipboard.unmark("com.woltlab.wcf.media", Array.from(this._mediaToInsert.keys()));
+ }
+
+ this._mediaToInsert = new Map<number, Media>();
+ this._mediaToInsertByClipboard = false;
+
+ // close manager dialog
+ if (closeEditor) {
+ UiDialog.close(this);
+ }
+ }
+
+ /**
+ * Inserts a single media item into the editor.
+ */
+ protected _insertMediaItem(thumbnailSize: string | undefined, media: Media): void {
+ if (media.isImage) {
+ let available = "";
+ ["small", "medium", "large", "original"].some((size) => {
+ if (media[size + "ThumbnailHeight"] != 0) {
+ available = size;
+
+ if (thumbnailSize == size) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+
+ thumbnailSize = available;
+
+ if (!thumbnailSize) {
+ thumbnailSize = "original";
+ }
+
+ let link = media.link;
+ if (thumbnailSize !== "original") {
+ link = media[thumbnailSize + "ThumbnailLink"];
+ }
+
+ this._options.editor!.insert.html(
+ `<img src="${link}" class="woltlabSuiteMedia" data-media-id="${media.mediaID}" data-media-size="${thumbnailSize}">`,
+ );
+ } else {
+ this._options.editor!.insert.text(`[wsm='${media.mediaID}'][/wsm]`);
+ }
+ }
+
+ /**
+ * Is called after media files are successfully uploaded to insert copied media.
+ */
+ protected _mediaUploaded(data: MediaUploadSuccessEventData): void {
+ if (this._uploadId !== null && this._upload === data.upload) {
+ if (
+ this._uploadId === data.uploadId ||
+ (Array.isArray(this._uploadId) && this._uploadId.indexOf(data.uploadId) !== -1)
+ ) {
+ this._mediaToInsert = new Map<number, Media>(data.media.entries());
+ this._insertMedia(null, "medium", false);
+
+ this._uploadId = null;
+ }
+ }
+ }
+
+ /**
+ * Handles clicking on the insert button.
+ */
+ protected _openInsertDialog(event: Event): void {
+ const target = event.currentTarget as HTMLElement;
+
+ this.insertMedia([~~target.dataset.objectId!]);
+ }
+
+ /**
+ * Is called to insert the media files with the given ids into an editor.
+ */
+ public clipboardInsertMedia(mediaIds: number[]): void {
+ this.insertMedia(mediaIds, true);
+ }
+
+ /**
+ * Prepares insertion of the media files with the given ids.
+ */
+ public insertMedia(mediaIds: number[], insertedByClipboard?: boolean): void {
+ this._mediaToInsert = new Map<number, Media>();
+ this._mediaToInsertByClipboard = insertedByClipboard || false;
+
+ // open the insert dialog if all media files are images
+ let imagesOnly = true;
+ mediaIds.forEach((mediaId) => {
+ const media = this._media.get(mediaId)!;
+ this._mediaToInsert.set(media.mediaID, media);
+
+ if (!media.isImage) {
+ imagesOnly = false;
+ }
+ });
+
+ if (imagesOnly) {
+ const thumbnailSizes = this._getThumbnailSizes();
+ if (thumbnailSizes.length) {
+ UiDialog.close(this);
+ const dialogId = this._getInsertDialogId();
+ if (UiDialog.getDialog(dialogId)) {
+ UiDialog.openStatic(dialogId, null);
+ } else {
+ this._buildInsertDialog();
+ }
+ } else {
+ this._insertMedia(undefined, "original");
+ }
+ } else {
+ this._insertMedia();
+ }
+ }
+
+ public getMode(): string {
+ return "editor";
+ }
+
+ public setupMediaElement(media: Media, mediaElement: HTMLElement): void {
+ super.setupMediaElement(media, mediaElement);
+
+ // add media insertion icon
+ const buttons = mediaElement.querySelector("nav.buttonGroupNavigation > ul")!;
+
+ const listItem = document.createElement("li");
+ listItem.className = "jsMediaInsertButton";
+ listItem.dataset.objectId = media.mediaID.toString();
+ buttons.appendChild(listItem);
+
+ listItem.innerHTML = `
+ <a>
+ <span class="icon icon16 fa-plus jsTooltip" title="${Language.get("wcf.global.button.insert")}"></span>
+ <span class="invisible">${Language.get("wcf.global.button.insert")}</span>
+ </a>`;
+ }
+}
+
+Core.enableLegacyInheritance(MediaManagerEditor);
+
+export = MediaManagerEditor;
/**
* Initializes modules required for media clipboard.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Media/Clipboard
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Clipboard
+ * @woltlabExcludeBundle tiny
*/
-define([
- 'Ajax',
- 'Dom/ChangeListener',
- 'EventHandler',
- 'Language',
- 'Ui/Dialog',
- 'Ui/Notification',
- 'WoltLabSuite/Core/Controller/Clipboard',
- 'WoltLabSuite/Core/Media/Editor',
- 'WoltLabSuite/Core/Media/List/Upload'
- ],
- function(
- Ajax,
- DomChangeListener,
- EventHandler,
- Language,
- UiDialog,
- UiNotification,
- Clipboard,
- MediaEditor,
- MediaListUpload
- ) {
- "use strict";
-
- if (!COMPILER_TARGET_DEFAULT) {
- var Fake = function() {};
- Fake.prototype = {
- init: function() {},
- _ajaxSetup: function() {},
- _ajaxSuccess: function() {},
- _clipboardAction: function() {},
- _dialogSetup: function() {},
- _edit: function() {},
- _setCategory: function() {}
- };
- return Fake;
- }
-
- var _clipboardObjectIds = [];
- var _didInit = false;
- var _mediaManager;
-
- /**
- * @exports WoltLabSuite/Core/Media/Clipboard
- */
- return {
- init: function(pageClassName, hasMarkedItems, mediaManager) {
- if (!_didInit) {
- Clipboard.setup({
- hasMarkedItems: hasMarkedItems,
- pageClassName: pageClassName
- });
-
- EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.media', this._clipboardAction.bind(this));
-
- _didInit = true;
- }
-
- _mediaManager = mediaManager;
- },
-
- /**
- * Returns the data used to setup the AJAX request object.
- *
- * @return {object} setup data
- */
- _ajaxSetup: function() {
- return {
- data: {
- className: 'wcf\\data\\media\\MediaAction'
- }
- }
- },
-
- /**
- * Handles successful AJAX request.
- *
- * @param {object} data response data
- */
- _ajaxSuccess: function(data) {
- switch (data.actionName) {
- case 'getSetCategoryDialog':
- UiDialog.open(this, data.returnValues.template);
-
- break;
-
- case 'setCategory':
- UiDialog.close(this);
-
- UiNotification.show();
-
- Clipboard.reload();
-
- break;
- }
- },
-
- /**
- * Returns the data used to setup the dialog.
- *
- * @return {object} setup data
- */
- _dialogSetup: function() {
- return {
- id: 'mediaSetCategoryDialog',
- options: {
- onSetup: function(content) {
- elBySel('button', content).addEventListener(WCF_CLICK_EVENT, function(event) {
- event.preventDefault();
-
- this._setCategory(~~elBySel('select[name="categoryID"]', content).value);
-
- event.currentTarget.disabled = true;
- }.bind(this));
- }.bind(this),
- title: Language.get('wcf.media.setCategory')
- },
- source: null
- }
- },
-
- /**
- * Handles successful clipboard actions.
- *
- * @param {object} actionData
- */
- _clipboardAction: function(actionData) {
- var mediaIds = actionData.data.parameters.objectIDs;
-
- switch (actionData.data.actionName) {
- case 'com.woltlab.wcf.media.delete':
- // only consider events if the action has been executed
- if (actionData.responseData !== null) {
- _mediaManager.clipboardDeleteMedia(mediaIds);
- }
-
- break;
-
- case 'com.woltlab.wcf.media.insert':
- _mediaManager.clipboardInsertMedia(mediaIds);
-
- break;
-
- case 'com.woltlab.wcf.media.setCategory':
- _clipboardObjectIds = mediaIds;
-
- Ajax.api(this, {
- actionName: 'getSetCategoryDialog'
- });
-
- break;
- }
- },
-
- /**
- * Sets the category of the marked media files.
- *
- * @param {int} categoryID selected category id
- */
- _setCategory: function(categoryID) {
- Ajax.api(this, {
- actionName: 'setCategory',
- objectIDs: _clipboardObjectIds,
- parameters: {
- categoryID: categoryID
- }
- });
- },
-
- /**
- * Sets the currently active media manager.
- *
- * @param {WoltLabSuite/Core/Media/Manager/Base} mediaManager
- */
- setMediaManager: function(mediaManager) {
- _mediaManager = mediaManager;
- }
- }
+define(["require", "exports", "tslib", "../Controller/Clipboard", "../Ui/Notification", "../Ui/Dialog", "../Event/Handler", "../Language", "../Ajax"], function (require, exports, tslib_1, Clipboard, UiNotification, UiDialog, EventHandler, Language, Ajax) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
- exports.init = void 0;
++ exports.setMediaManager = exports.init = void 0;
+ Clipboard = tslib_1.__importStar(Clipboard);
+ UiNotification = tslib_1.__importStar(UiNotification);
+ UiDialog = tslib_1.__importStar(UiDialog);
+ EventHandler = tslib_1.__importStar(EventHandler);
+ Language = tslib_1.__importStar(Language);
+ Ajax = tslib_1.__importStar(Ajax);
+ let _mediaManager;
++ const _didInit = false;
+ class MediaClipboard {
+ _ajaxSetup() {
+ return {
+ data: {
+ className: "wcf\\data\\media\\MediaAction",
+ },
+ };
+ }
+ _ajaxSuccess(data) {
+ switch (data.actionName) {
+ case "getSetCategoryDialog":
+ UiDialog.open(this, data.returnValues.template);
+ break;
+ case "setCategory":
+ UiDialog.close(this);
+ UiNotification.show();
+ Clipboard.reload();
+ break;
+ }
+ }
+ _dialogSetup() {
+ return {
+ id: "mediaSetCategoryDialog",
+ options: {
+ onSetup: (content) => {
+ content.querySelector("button").addEventListener("click", (event) => {
+ event.preventDefault();
+ const category = content.querySelector('select[name="categoryID"]');
+ setCategory(~~category.value);
+ const target = event.currentTarget;
+ target.disabled = true;
+ });
+ },
+ title: Language.get("wcf.media.setCategory"),
+ },
+ source: null,
+ };
+ }
+ }
+ const ajax = new MediaClipboard();
+ let clipboardObjectIds = [];
+ /**
+ * Handles successful clipboard actions.
+ */
+ function clipboardAction(actionData) {
+ const mediaIds = actionData.data.parameters.objectIDs;
+ switch (actionData.data.actionName) {
+ case "com.woltlab.wcf.media.delete":
+ // only consider events if the action has been executed
+ if (actionData.responseData !== null) {
+ _mediaManager.clipboardDeleteMedia(mediaIds);
+ }
+ break;
+ case "com.woltlab.wcf.media.insert": {
+ const mediaManagerEditor = _mediaManager;
+ mediaManagerEditor.clipboardInsertMedia(mediaIds);
+ break;
+ }
+ case "com.woltlab.wcf.media.setCategory":
+ clipboardObjectIds = mediaIds;
+ Ajax.api(ajax, {
+ actionName: "getSetCategoryDialog",
+ });
+ break;
+ }
+ }
+ /**
+ * Sets the category of the marked media files.
+ */
+ function setCategory(categoryID) {
+ Ajax.api(ajax, {
+ actionName: "setCategory",
+ objectIDs: clipboardObjectIds,
+ parameters: {
+ categoryID: categoryID,
+ },
+ });
+ }
+ function init(pageClassName, hasMarkedItems, mediaManager) {
- Clipboard.setup({
- hasMarkedItems: hasMarkedItems,
- pageClassName: pageClassName,
- });
++ if (!_didInit) {
++ Clipboard.setup({
++ hasMarkedItems: hasMarkedItems,
++ pageClassName: pageClassName,
++ });
++ EventHandler.add("com.woltlab.wcf.clipboard", "com.woltlab.wcf.media", (data) => clipboardAction(data));
++ }
+ _mediaManager = mediaManager;
- EventHandler.add("com.woltlab.wcf.clipboard", "com.woltlab.wcf.media", (data) => clipboardAction(data));
+ }
+ exports.init = init;
++ function setMediaManager(mediaManager) {
++ _mediaManager = mediaManager;
++ }
++ exports.setMediaManager = setMediaManager;
});
/**
* Provides the media manager dialog.
- *
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Media/Manager/Base
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Manager/Base
+ * @woltlabExcludeBundle tiny
*/
-define(
- [
- 'Core', 'Dictionary', 'Dom/ChangeListener', 'Dom/Traverse',
- 'Dom/Util', 'EventHandler', 'Language', 'List',
- 'Permission', 'Ui/Dialog', 'Ui/Notification', 'WoltLabSuite/Core/Controller/Clipboard',
- 'WoltLabSuite/Core/Media/Editor', 'WoltLabSuite/Core/Media/Upload', 'WoltLabSuite/Core/Media/Manager/Search', 'StringUtil',
- 'WoltLabSuite/Core/Ui/Pagination',
- 'WoltLabSuite/Core/Media/Clipboard'
- ],
- function(
- Core, Dictionary, DomChangeListener, DomTraverse,
- DomUtil, EventHandler, Language, List,
- Permission, UiDialog, UiNotification, Clipboard,
- MediaEditor, MediaUpload, MediaManagerSearch, StringUtil,
- UiPagination,
- MediaClipboard
- )
-{
- "use strict";
-
- if (!COMPILER_TARGET_DEFAULT) {
- var Fake = function() {};
- Fake.prototype = {
- _addButtonEventListeners: function() {},
- _click: function() {},
- _dialogClose: function() {},
- _dialogInit: function() {},
- _dialogSetup: function() {},
- _dialogShow: function() {},
- _editMedia: function() {},
- _editorClose: function() {},
- _editorSuccess: function() {},
- _removeClipboardCheckboxes: function() {},
- _setMedia: function() {},
- addMedia: function() {},
- clipboardDeleteMedia: function() {},
- getDialog: function() {},
- getMode: function() {},
- getOption: function() {},
- removeMedia: function() {},
- resetMedia: function() {},
- setMedia: function() {},
- setupMediaElement: function() {}
- };
- return Fake;
- }
-
- var _mediaManagerCounter = 0;
-
- /**
- * @constructor
- */
- function MediaManagerBase(options) {
- this._options = Core.extend({
- dialogTitle: Language.get('wcf.media.manager'),
- imagesOnly: false,
- minSearchLength: 3
- }, options);
-
- this._id = 'mediaManager' + _mediaManagerCounter++;
- this._listItems = new Dictionary();
- this._media = new Dictionary();
- this._mediaManagerMediaList = null;
- this._search = null;
- this._upload = null;
- this._forceClipboard = false;
- this._hadInitiallyMarkedItems = false;
- this._pagination = null;
-
- if (Permission.get('admin.content.cms.canManageMedia')) {
- this._mediaEditor = new MediaEditor(this);
- }
-
- DomChangeListener.add('WoltLabSuite/Core/Media/Manager', this._addButtonEventListeners.bind(this));
-
- EventHandler.add('com.woltlab.wcf.media.upload', 'success', this._openEditorAfterUpload.bind(this));
- }
- MediaManagerBase.prototype = {
- /**
- * Adds click event listeners to media buttons.
- */
- _addButtonEventListeners: function() {
- if (!this._mediaManagerMediaList) return;
-
- var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI');
- for (var i = 0, length = listItems.length; i < length; i++) {
- var listItem = listItems[i];
-
- if (Permission.get('admin.content.cms.canManageMedia')) {
- var editIcon = elByClass('jsMediaEditButton', listItem)[0];
- if (editIcon) {
- editIcon.classList.remove('jsMediaEditButton');
- editIcon.addEventListener(WCF_CLICK_EVENT, this._editMedia.bind(this));
- }
- }
- }
- },
-
- /**
- * Is called when a new category is selected.
- */
- _categoryChange: function() {
- this._search.search();
- },
-
- /**
- * Handles clicks on the media manager button.
- *
- * @param {object} event event object
- */
- _click: function(event) {
- event.preventDefault();
-
- UiDialog.open(this);
- },
-
- /**
- * Is called if the media manager dialog is closed.
- */
- _dialogClose: function() {
- // only show media clipboard if editor is open
- if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) {
- Clipboard.hideEditor('com.woltlab.wcf.media');
- }
- },
-
- /**
- * Initializes the dialog when first loaded.
- *
- * @param {string} content dialog content
- * @param {object} data AJAX request's response data
- */
- _dialogInit: function(content, data) {
- // store media data locally
- var media = data.returnValues.media || { };
- for (var mediaId in media) {
- if (objOwns(media, mediaId)) {
- this._media.set(~~mediaId, media[mediaId]);
- }
- }
-
- this._initPagination(~~data.returnValues.pageCount);
-
- this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems;
- },
-
- /**
- * Returns all data to setup the media manager dialog.
- *
- * @return {object} dialog setup data
- */
- _dialogSetup: function() {
- return {
- id: this._id,
- options: {
- onClose: this._dialogClose.bind(this),
- onShow: this._dialogShow.bind(this),
- title: this._options.dialogTitle
- },
- source: {
- after: this._dialogInit.bind(this),
- data: {
- actionName: 'getManagementDialog',
- className: 'wcf\\data\\media\\MediaAction',
- parameters: {
- mode: this.getMode(),
- imagesOnly: this._options.imagesOnly
- }
- }
- }
- };
- },
-
- /**
- * Is called if the media manager dialog is shown.
- */
- _dialogShow: function() {
- if (!this._mediaManagerMediaList) {
- var dialog = this.getDialog();
-
- this._mediaManagerMediaList = elByClass('mediaManagerMediaList', dialog)[0];
-
- this._mediaCategorySelect = elBySel('.mediaManagerCategoryList > select', dialog);
- if (this._mediaCategorySelect) {
- this._mediaCategorySelect.addEventListener('change', this._categoryChange.bind(this));
- }
-
- // store list items locally
- var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI');
- for (var i = 0, length = listItems.length; i < length; i++) {
- var listItem = listItems[i];
-
- this._listItems.set(~~elData(listItem, 'object-id'), listItem);
- }
-
- if (Permission.get('admin.content.cms.canManageMedia')) {
- var uploadButton = elByClass('mediaManagerMediaUploadButton', UiDialog.getDialog(this).dialog)[0];
- this._upload = new MediaUpload(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList), {
- mediaManager: this
- });
-
- var deleteAction = new WCF.Action.Delete('wcf\\data\\media\\MediaAction', '.mediaFile');
- deleteAction._didTriggerEffect = function(element) {
- this.removeMedia(elData(element[0], 'object-id'));
- }.bind(this);
- }
-
- if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) {
- MediaClipboard.init(
- 'menuManagerDialog-' + this.getMode(),
- this._hadInitiallyMarkedItems ? true : false,
- this
- );
- }
- else {
- this._removeClipboardCheckboxes();
- }
-
- this._search = new MediaManagerSearch(this);
-
- if (!listItems.length) {
- this._search.hideSearch();
- }
- }
- else {
- MediaClipboard.setMediaManager(this);
- }
-
- // only show media clipboard if editor is open
- if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) {
- Clipboard.showEditor('com.woltlab.wcf.media');
- }
- },
-
- /**
- * Opens the media editor for a media file.
- *
- * @param {Event} event event object for clicks on edit icons
- */
- _editMedia: function(event) {
- if (!Permission.get('admin.content.cms.canManageMedia')) {
- throw new Error("You are not allowed to edit media files.");
- }
-
- UiDialog.close(this);
-
- this._mediaEditor.edit(this._media.get(~~elData(event.currentTarget, 'object-id')));
- },
-
- /**
- * Re-opens the manager dialog after closing the editor dialog.
- */
- _editorClose: function() {
- UiDialog.open(this);
- },
-
- /**
- * Re-opens the manager dialog and updates the media data after
- * successfully editing a media file.
- *
- * @param {object} media updated media file data
- * @param {integer} oldCategoryId old category id
- * @param {boolean} closedEditorDialog
- */
- _editorSuccess: function(media, oldCategoryId, closedEditorDialog = true) {
- // if the category changed of media changed and category
- // is selected, check if media list needs to be refreshed
- if (this._mediaCategorySelect) {
- var selectedCategoryId = ~~this._mediaCategorySelect.value;
-
- if (selectedCategoryId) {
- var newCategoryId = ~~media.categoryID;
-
- if (oldCategoryId != newCategoryId && (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId)) {
- this._search.search();
- }
- }
- }
-
- if (closedEditorDialog) {
- UiDialog.open(this);
- }
-
- this._media.set(~~media.mediaID, media);
-
- var listItem = this._listItems.get(~~media.mediaID);
- var p = elByClass('mediaTitle', listItem)[0];
- if (media.isMultilingual) {
- if (media.title && media.title[LANGUAGE_ID]) {
- p.textContent = media.title[LANGUAGE_ID];
- }
- else {
- p.textContent = media.filename;
- }
- }
- else {
- if (media.title && media.title[media.languageID]) {
- p.textContent = media.title[media.languageID];
- }
- else {
- p.textContent = media.filename;
- }
- }
-
- var thumbnail = elByClass('mediaThumbnail', listItem)[0];
- thumbnail.innerHTML = media.elementTag;
- // Bust browser cache by adding additional parameter.
- var imgs = elByTag('img', thumbnail);
- if (imgs.length) {
- imgs[0].src += '&refresh=' + Date.now();
- }
- },
-
- /**
- * Initializes the dialog pagination.
- *
- * @param {integer} pageCount
- * @param {integer} pageNo
- */
- _initPagination: function(pageCount, pageNo) {
- if (pageNo === undefined) pageNo = 1;
-
- if (pageCount > 1) {
- var newPagination = elCreate('div');
- newPagination.className = 'paginationBottom jsPagination';
- DomUtil.replaceElement(elBySel('.jsPagination', UiDialog.getDialog(this).content), newPagination);
-
- this._pagination = new UiPagination(newPagination, {
- activePage: pageNo,
- callbackSwitch: this._search.search.bind(this._search),
- maxPage: pageCount
- });
- }
- else if (this._pagination) {
- elHide(this._pagination.getElement());
- }
- },
-
- /**
- * Removes all media clipboard checkboxes.
- */
- _removeClipboardCheckboxes: function() {
- var checkboxes = elByClass('mediaCheckbox', this._mediaManagerMediaList);
- while (checkboxes.length) {
- elRemove(checkboxes[0]);
- }
- },
-
- /**
- * Opens the media editor after uploading a single file.
- *
- * @param {object} data upload event data
- * @since 5.2
- */
- _openEditorAfterUpload: function(data) {
- if (data.upload === this._upload && !data.isMultiFileUpload && !this._upload.hasPendingUploads()) {
- var keys = Object.keys(data.media);
-
- if (keys.length) {
- UiDialog.close(this);
-
- this._mediaEditor.edit(this._media.get(~~data.media[keys[0]].mediaID));
- }
- }
- },
-
- /**
- * Sets the displayed media (after a search).
- *
- * @param {Dictionary} media media to be set as active
- */
- _setMedia: function(media) {
- if (Core.isPlainObject(media)) {
- this._media = Dictionary.fromObject(media);
- }
- else {
- this._media = media;
- }
-
- var info = DomTraverse.nextByClass(this._mediaManagerMediaList, 'info');
-
- if (this._media.size) {
- if (info) {
- elHide(info);
- }
- }
- else {
- if (info === null) {
- info = elCreate('p');
- info.className = 'info';
- info.textContent = Language.get('wcf.media.search.noResults');
- }
-
- elShow(info);
- DomUtil.insertAfter(info, this._mediaManagerMediaList);
- }
-
- var mediaListItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI');
- for (var i = 0, length = mediaListItems.length; i < length; i++) {
- var listItem = mediaListItems[i];
-
- if (!this._media.has(elData(listItem, 'object-id'))) {
- elHide(listItem);
- }
- else {
- elShow(listItem);
- }
- }
-
- DomChangeListener.trigger();
-
- if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) {
- Clipboard.reload();
- }
- else {
- this._removeClipboardCheckboxes();
- }
- },
-
- /**
- * Adds a media file to the manager.
- *
- * @param {object} media data of the media file
- * @param {Element} listItem list item representing the file
- */
- addMedia: function(media, listItem) {
- if (!media.languageID) media.isMultilingual = 1;
-
- this._media.set(~~media.mediaID, media);
- this._listItems.set(~~media.mediaID, listItem);
-
- if (this._listItems.size === 1) {
- this._search.showSearch();
- }
- },
-
- /**
- * Is called after the media files with the given ids have been deleted via clipboard.
- *
- * @param {int[]} mediaIds ids of deleted media files
- */
- clipboardDeleteMedia: function(mediaIds) {
- for (var i = 0, length = mediaIds.length; i < length; i++) {
- this.removeMedia(~~mediaIds[i], true);
- }
-
- UiNotification.show();
- },
-
- /**
- * Returns the id of the currently selected category or `0` if no category is selected.
- *
- * @return {integer}
- */
- getCategoryId: function() {
- if (this._mediaCategorySelect) {
- return this._mediaCategorySelect.value;
- }
-
- return 0;
- },
-
- /**
- * Returns the media manager dialog element.
- *
- * @return {Element} media manager dialog
- */
- getDialog: function() {
- return UiDialog.getDialog(this).dialog;
- },
-
- /**
- * Returns the mode of the media manager.
- *
- * @return {string}
- */
- getMode: function() {
- return '';
- },
-
- /**
- * Returns the media manager option with the given name.
- *
- * @param {string} name option name
- * @return {mixed} option value or null
- */
- getOption: function(name) {
- if (this._options[name]) {
- return this._options[name];
- }
-
- return null;
- },
-
- /**
- * Removes a media file.
- *
- * @param {int} mediaId id of the removed media file
- */
- removeMedia: function(mediaId) {
- if (this._listItems.has(mediaId)) {
- // remove list item
- try {
- elRemove(this._listItems.get(mediaId));
- }
- catch (e) {
- // ignore errors if item has already been removed like by WCF.Action.Delete
- }
-
- this._listItems.delete(mediaId);
- this._media.delete(mediaId);
- }
- },
-
- /**
- * Changes the displayed media to the previously displayed media.
- */
- resetMedia: function() {
- // calling WoltLabSuite/Core/Media/Manager/Search.search() reloads the first page of the dialog
- this._search.search();
- },
-
- /**
- * Sets the media files currently displayed.
- *
- * @param {object} media media data
- * @param {string} template
- * @param {object} additionalData
- */
- setMedia: function(media, template, additionalData) {
- var hasMedia = false;
- for (var mediaId in media) {
- if (objOwns(media, mediaId)) {
- hasMedia = true;
- }
- }
-
- var newListItems = [];
- if (hasMedia) {
- var ul = elCreate('ul');
- ul.innerHTML = template;
-
- var listItems = DomTraverse.childrenByTag(ul, 'LI');
- for (var i = 0, length = listItems.length; i < length; i++) {
- var listItem = listItems[i];
- if (!this._listItems.has(~~elData(listItem, 'object-id'))) {
- this._listItems.set(elData(listItem, 'object-id'), listItem);
-
- this._mediaManagerMediaList.appendChild(listItem);
- }
- }
- }
-
- this._initPagination(additionalData.pageCount, additionalData.pageNo);
-
- this._setMedia(media);
- },
-
- /**
- * Sets up a new media element.
- *
- * @param {object} media data of the media file
- * @param {HTMLElement} mediaElement element representing the media file
- */
- setupMediaElement: function(media, mediaElement) {
- var mediaInformation = DomTraverse.childByClass(mediaElement, 'mediaInformation');
-
- var buttonGroupNavigation = elCreate('nav');
- buttonGroupNavigation.className = 'jsMobileNavigation buttonGroupNavigation';
- mediaInformation.parentNode.appendChild(buttonGroupNavigation);
-
- var buttons = elCreate('ul');
- buttons.className = 'buttonList iconList';
- buttonGroupNavigation.appendChild(buttons);
-
- var listItem = elCreate('li');
- listItem.className = 'mediaCheckbox';
- buttons.appendChild(listItem);
-
- var a = elCreate('a');
- listItem.appendChild(a);
-
- var label = elCreate('label');
- a.appendChild(label);
-
- var checkbox = elCreate('input');
- checkbox.className = 'jsClipboardItem';
- elAttr(checkbox, 'type', 'checkbox');
- elData(checkbox, 'object-id', media.mediaID);
- label.appendChild(checkbox);
-
- if (Permission.get('admin.content.cms.canManageMedia')) {
- listItem = elCreate('li');
- listItem.className = 'jsMediaEditButton';
- elData(listItem, 'object-id', media.mediaID);
- buttons.appendChild(listItem);
-
- listItem.innerHTML = '<a><span class="icon icon16 fa-pencil jsTooltip" title="' + Language.get('wcf.global.button.edit') + '"></span> <span class="invisible">' + Language.get('wcf.global.button.edit') + '</span></a>';
-
- listItem = elCreate('li');
- listItem.className = 'jsDeleteButton';
- elData(listItem, 'object-id', media.mediaID);
-
- // use temporary title to not unescape html in filename
- var uuid = Core.getUuid();
- elData(listItem, 'confirm-message-html', StringUtil.unescapeHTML(Language.get('wcf.media.delete.confirmMessage', {
- title: uuid
- })).replace(uuid, StringUtil.escapeHTML(media.filename)));
- buttons.appendChild(listItem);
-
- listItem.innerHTML = '<a><span class="icon icon16 fa-times jsTooltip" title="' + Language.get('wcf.global.button.delete') + '"></span> <span class="invisible">' + Language.get('wcf.global.button.delete') + '</span></a>';
- }
- }
- };
-
- return MediaManagerBase;
+define(["require", "exports", "tslib", "../../Core", "../../Language", "../../Permission", "../../Dom/Change/Listener", "../../Event/Handler", "../../Dom/Traverse", "../../Dom/Util", "../../Ui/Dialog", "../../Controller/Clipboard", "../../Ui/Pagination", "../../Ui/Notification", "../../StringUtil", "./Search", "../Upload", "../Editor", "../Clipboard"], function (require, exports, tslib_1, Core, Language, Permission, DomChangeListener, EventHandler, DomTraverse, DomUtil, UiDialog, Clipboard, Pagination_1, UiNotification, StringUtil, Search_1, Upload_1, Editor_1, MediaClipboard) {
+ "use strict";
+ Core = tslib_1.__importStar(Core);
+ Language = tslib_1.__importStar(Language);
+ Permission = tslib_1.__importStar(Permission);
+ DomChangeListener = tslib_1.__importStar(DomChangeListener);
+ EventHandler = tslib_1.__importStar(EventHandler);
+ DomTraverse = tslib_1.__importStar(DomTraverse);
+ DomUtil = tslib_1.__importStar(DomUtil);
+ UiDialog = tslib_1.__importStar(UiDialog);
+ Clipboard = tslib_1.__importStar(Clipboard);
+ Pagination_1 = tslib_1.__importDefault(Pagination_1);
+ UiNotification = tslib_1.__importStar(UiNotification);
+ StringUtil = tslib_1.__importStar(StringUtil);
+ Search_1 = tslib_1.__importDefault(Search_1);
+ Upload_1 = tslib_1.__importDefault(Upload_1);
+ Editor_1 = tslib_1.__importDefault(Editor_1);
+ MediaClipboard = tslib_1.__importStar(MediaClipboard);
+ let mediaManagerCounter = 0;
+ class MediaManager {
+ constructor(options) {
+ this._forceClipboard = false;
+ this._hadInitiallyMarkedItems = false;
+ this._listItems = new Map();
+ this._media = new Map();
+ this._mediaEditor = null;
+ this._mediaManagerMediaList = null;
+ this._pagination = null;
+ this._search = null;
+ this._upload = null;
+ this._options = Core.extend({
+ dialogTitle: Language.get("wcf.media.manager"),
+ imagesOnly: false,
+ minSearchLength: 3,
+ }, options);
+ this._id = `mediaManager${mediaManagerCounter++}`;
+ if (Permission.get("admin.content.cms.canManageMedia")) {
+ this._mediaEditor = new Editor_1.default(this);
+ }
+ DomChangeListener.add("WoltLabSuite/Core/Media/Manager", () => this._addButtonEventListeners());
+ EventHandler.add("com.woltlab.wcf.media.upload", "success", (data) => this._openEditorAfterUpload(data));
+ }
+ /**
+ * Adds click event listeners to media buttons.
+ */
+ _addButtonEventListeners() {
+ if (!this._mediaManagerMediaList || !Permission.get("admin.content.cms.canManageMedia"))
+ return;
+ DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => {
+ const editIcon = listItem.querySelector(".jsMediaEditButton");
+ if (editIcon) {
+ editIcon.classList.remove("jsMediaEditButton");
+ editIcon.addEventListener("click", (ev) => this._editMedia(ev));
+ }
+ });
+ }
+ /**
+ * Is called when a new category is selected.
+ */
+ _categoryChange() {
+ this._search.search();
+ }
+ /**
+ * Handles clicks on the media manager button.
+ */
+ _click(event) {
+ event.preventDefault();
+ UiDialog.open(this);
+ }
+ /**
+ * Is called if the media manager dialog is closed.
+ */
+ _dialogClose() {
+ // only show media clipboard if editor is open
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ Clipboard.hideEditor("com.woltlab.wcf.media");
+ }
+ }
+ /**
+ * Initializes the dialog when first loaded.
+ */
+ _dialogInit(content, data) {
+ // store media data locally
+ Object.entries(data.returnValues.media || {}).forEach(([mediaId, media]) => {
+ this._media.set(~~mediaId, media);
+ });
+ this._initPagination(~~data.returnValues.pageCount);
+ this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems > 0;
+ }
+ /**
+ * Returns all data to setup the media manager dialog.
+ */
+ _dialogSetup() {
+ return {
+ id: this._id,
+ options: {
+ onClose: () => this._dialogClose(),
+ onShow: () => this._dialogShow(),
+ title: this._options.dialogTitle,
+ },
+ source: {
+ after: (content, data) => this._dialogInit(content, data),
+ data: {
+ actionName: "getManagementDialog",
+ className: "wcf\\data\\media\\MediaAction",
+ parameters: {
+ mode: this.getMode(),
+ imagesOnly: this._options.imagesOnly,
+ },
+ },
+ },
+ };
+ }
+ /**
+ * Is called if the media manager dialog is shown.
+ */
+ _dialogShow() {
+ if (!this._mediaManagerMediaList) {
+ const dialog = this.getDialog();
+ this._mediaManagerMediaList = dialog.querySelector(".mediaManagerMediaList");
+ this._mediaCategorySelect = dialog.querySelector(".mediaManagerCategoryList > select");
+ if (this._mediaCategorySelect) {
+ this._mediaCategorySelect.addEventListener("change", () => this._categoryChange());
+ }
+ // store list items locally
+ const listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI");
+ listItems.forEach((listItem) => {
+ this._listItems.set(~~listItem.dataset.objectId, listItem);
+ });
+ if (Permission.get("admin.content.cms.canManageMedia")) {
+ const uploadButton = UiDialog.getDialog(this).dialog.querySelector(".mediaManagerMediaUploadButton");
+ this._upload = new Upload_1.default(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList), {
+ mediaManager: this,
+ });
+ EventHandler.add("WoltLabSuite/Core/Ui/Object/Action", "delete", (data) => this.removeMedia(~~data.objectElement.dataset.objectId));
+ }
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ MediaClipboard.init("menuManagerDialog-" + this.getMode(), this._hadInitiallyMarkedItems ? true : false, this);
+ }
+ else {
+ this._removeClipboardCheckboxes();
+ }
+ this._search = new Search_1.default(this);
+ if (!listItems.length) {
+ this._search.hideSearch();
+ }
+ }
++ else {
++ MediaClipboard.setMediaManager(this);
++ }
+ // only show media clipboard if editor is open
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ Clipboard.showEditor();
+ }
+ }
+ /**
+ * Opens the media editor for a media file.
+ */
+ _editMedia(event) {
+ if (!Permission.get("admin.content.cms.canManageMedia")) {
+ throw new Error("You are not allowed to edit media files.");
+ }
+ UiDialog.close(this);
+ const target = event.currentTarget;
+ this._mediaEditor.edit(this._media.get(~~target.dataset.objectId));
+ }
+ /**
+ * Re-opens the manager dialog after closing the editor dialog.
+ */
+ _editorClose() {
+ UiDialog.open(this);
+ }
+ /**
+ * Re-opens the manager dialog and updates the media data after successfully editing a media file.
+ */
+ _editorSuccess(media, oldCategoryId, closedEditorDialog = true) {
+ // if the category changed of media changed and category
+ // is selected, check if media list needs to be refreshed
+ if (this._mediaCategorySelect) {
+ const selectedCategoryId = ~~this._mediaCategorySelect.value;
+ if (selectedCategoryId) {
+ const newCategoryId = ~~media.categoryID;
+ if (oldCategoryId != newCategoryId &&
+ (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId)) {
+ this._search.search();
+ }
+ }
+ }
+ if (closedEditorDialog) {
+ UiDialog.open(this);
+ }
+ this._media.set(~~media.mediaID, media);
+ const listItem = this._listItems.get(~~media.mediaID);
+ const p = listItem.querySelector(".mediaTitle");
+ if (media.isMultilingual) {
+ if (media.title && media.title[window.LANGUAGE_ID]) {
+ p.textContent = media.title[window.LANGUAGE_ID];
+ }
+ else {
+ p.textContent = media.filename;
+ }
+ }
+ else {
+ if (media.title && media.title[media.languageID]) {
+ p.textContent = media.title[media.languageID];
+ }
+ else {
+ p.textContent = media.filename;
+ }
+ }
+ const thumbnail = listItem.querySelector(".mediaThumbnail");
+ thumbnail.innerHTML = media.elementTag;
+ // Bust browser cache by adding additional parameter.
+ const img = thumbnail.querySelector("img");
+ if (img) {
+ img.src += `&refresh=${Date.now()}`;
+ }
+ }
+ /**
+ * Initializes the dialog pagination.
+ */
+ _initPagination(pageCount, pageNo) {
+ if (pageNo === undefined)
+ pageNo = 1;
+ if (pageCount > 1) {
+ const newPagination = document.createElement("div");
+ newPagination.className = "paginationBottom jsPagination";
+ DomUtil.replaceElement(UiDialog.getDialog(this).content.querySelector(".jsPagination"), newPagination);
+ this._pagination = new Pagination_1.default(newPagination, {
+ activePage: pageNo,
+ callbackSwitch: (pageNo) => this._search.search(pageNo),
+ maxPage: pageCount,
+ });
+ }
+ else if (this._pagination) {
+ DomUtil.hide(this._pagination.getElement());
+ }
+ }
+ /**
+ * Removes all media clipboard checkboxes.
+ */
+ _removeClipboardCheckboxes() {
+ this._mediaManagerMediaList.querySelectorAll(".mediaCheckbox").forEach((el) => el.remove());
+ }
+ /**
+ * Opens the media editor after uploading a single file.
+ *
+ * @since 5.2
+ */
+ _openEditorAfterUpload(data) {
+ if (data.upload === this._upload && !data.isMultiFileUpload && !this._upload.hasPendingUploads()) {
+ const keys = Object.keys(data.media);
+ if (keys.length) {
+ UiDialog.close(this);
+ this._mediaEditor.edit(this._media.get(~~data.media[keys[0]].mediaID));
+ }
+ }
+ }
+ /**
+ * Sets the displayed media (after a search).
+ */
+ _setMedia(media) {
+ this._media = new Map(Object.entries(media).map(([mediaId, media]) => [~~mediaId, media]));
+ let info = DomTraverse.nextByClass(this._mediaManagerMediaList, "info");
+ if (this._media.size) {
+ if (info) {
+ DomUtil.hide(info);
+ }
+ }
+ else {
+ if (info === null) {
+ info = document.createElement("p");
+ info.className = "info";
+ info.textContent = Language.get("wcf.media.search.noResults");
+ }
+ DomUtil.show(info);
+ DomUtil.insertAfter(info, this._mediaManagerMediaList);
+ }
+ DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => {
+ if (!this._media.has(~~listItem.dataset.objectId)) {
+ DomUtil.hide(listItem);
+ }
+ else {
+ DomUtil.show(listItem);
+ }
+ });
+ DomChangeListener.trigger();
+ if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
+ Clipboard.reload();
+ }
+ else {
+ this._removeClipboardCheckboxes();
+ }
+ }
+ /**
+ * Adds a media file to the manager.
+ */
+ addMedia(media, listItem) {
+ if (!media.languageID)
+ media.isMultilingual = 1;
+ this._media.set(~~media.mediaID, media);
+ this._listItems.set(~~media.mediaID, listItem);
+ if (this._listItems.size === 1) {
+ this._search.showSearch();
+ }
+ }
+ /**
+ * Is called after the media files with the given ids have been deleted via clipboard.
+ */
+ clipboardDeleteMedia(mediaIds) {
+ mediaIds.forEach((mediaId) => {
+ this.removeMedia(~~mediaId);
+ });
+ UiNotification.show();
+ }
+ /**
+ * Returns the id of the currently selected category or `0` if no category is selected.
+ */
+ getCategoryId() {
+ if (this._mediaCategorySelect) {
+ return ~~this._mediaCategorySelect.value;
+ }
+ return 0;
+ }
+ /**
+ * Returns the media manager dialog element.
+ */
+ getDialog() {
+ return UiDialog.getDialog(this).dialog;
+ }
+ /**
+ * Returns the mode of the media manager.
+ */
+ getMode() {
+ return "";
+ }
+ /**
+ * Returns the media manager option with the given name.
+ */
+ getOption(name) {
+ if (this._options[name]) {
+ return this._options[name];
+ }
+ return null;
+ }
+ /**
+ * Removes a media file.
+ */
+ removeMedia(mediaId) {
+ if (this._listItems.has(mediaId)) {
+ // remove list item
+ try {
+ this._listItems.get(mediaId).remove();
+ }
+ catch (e) {
+ // ignore errors if item has already been removed by other code
+ }
+ this._listItems.delete(mediaId);
+ this._media.delete(mediaId);
+ }
+ }
+ /**
+ * Changes the displayed media to the previously displayed media.
+ */
+ resetMedia() {
+ // calling WoltLabSuite/Core/Media/Manager/Search.search() reloads the first page of the dialog
+ this._search.search();
+ }
+ /**
+ * Sets the media files currently displayed.
+ */
+ setMedia(media, template, additionalData) {
+ const hasMedia = Object.entries(media).length > 0;
+ if (hasMedia) {
+ const ul = document.createElement("ul");
+ ul.innerHTML = template;
+ DomTraverse.childrenByTag(ul, "LI").forEach((listItem) => {
+ if (!this._listItems.has(~~listItem.dataset.objectId)) {
+ this._listItems.set(~~listItem.dataset.objectId, listItem);
+ this._mediaManagerMediaList.appendChild(listItem);
+ }
+ });
+ }
+ this._initPagination(additionalData.pageCount, additionalData.pageNo);
+ this._setMedia(media);
+ }
+ /**
+ * Sets up a new media element.
+ */
+ setupMediaElement(media, mediaElement) {
+ const mediaInformation = DomTraverse.childByClass(mediaElement, "mediaInformation");
+ const buttonGroupNavigation = document.createElement("nav");
+ buttonGroupNavigation.className = "jsMobileNavigation buttonGroupNavigation";
+ mediaInformation.parentNode.appendChild(buttonGroupNavigation);
+ const buttons = document.createElement("ul");
+ buttons.className = "buttonList iconList";
+ buttonGroupNavigation.appendChild(buttons);
+ const listItem = document.createElement("li");
+ listItem.className = "mediaCheckbox";
+ buttons.appendChild(listItem);
+ const a = document.createElement("a");
+ listItem.appendChild(a);
+ const label = document.createElement("label");
+ a.appendChild(label);
+ const checkbox = document.createElement("input");
+ checkbox.className = "jsClipboardItem";
+ checkbox.type = "checkbox";
+ checkbox.dataset.objectId = media.mediaID.toString();
+ label.appendChild(checkbox);
+ if (Permission.get("admin.content.cms.canManageMedia")) {
+ const editButton = document.createElement("li");
+ editButton.className = "jsMediaEditButton";
+ editButton.dataset.objectId = media.mediaID.toString();
+ buttons.appendChild(editButton);
+ editButton.innerHTML = `
+ <a>
+ <span class="icon icon16 fa-pencil jsTooltip" title="${Language.get("wcf.global.button.edit")}"></span>
+ <span class="invisible">${Language.get("wcf.global.button.edit")}</span>
+ </a>`;
+ const deleteButton = document.createElement("li");
+ deleteButton.classList.add("jsObjectAction");
+ deleteButton.dataset.objectAction = "delete";
+ // use temporary title to not unescape html in filename
+ const uuid = Core.getUuid();
+ deleteButton.dataset.confirmMessage = StringUtil.unescapeHTML(Language.get("wcf.media.delete.confirmMessage", {
+ title: uuid,
+ })).replace(uuid, StringUtil.escapeHTML(media.filename));
+ buttons.appendChild(deleteButton);
+ deleteButton.innerHTML = `
+ <a>
+ <span class="icon icon16 fa-times jsTooltip" title="${Language.get("wcf.global.button.delete")}"></span>
+ <span class="invisible">${Language.get("wcf.global.button.delete")}</span>
+ </a>`;
+ }
+ }
+ }
+ Core.enableLegacyInheritance(MediaManager);
+ return MediaManager;
});
/**
* Provides the media manager dialog for selecting media for Redactor editors.
*
- * @author Matthias Schmidt
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Media/Manager/Editor
+ * @author Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Manager/Editor
+ * @woltlabExcludeBundle tiny
*/
-define(['Core', 'Dictionary', 'Dom/Traverse', 'EventHandler', 'Language', 'Permission', 'Ui/Dialog', 'WoltLabSuite/Core/Controller/Clipboard', 'WoltLabSuite/Core/Media/Manager/Base'],
- function(Core, Dictionary, DomTraverse, EventHandler, Language, Permission, UiDialog, ControllerClipboard, MediaManagerBase) {
- "use strict";
-
- if (!COMPILER_TARGET_DEFAULT) {
- var Fake = function() {};
- Fake.prototype = {
- _addButtonEventListeners: function() {},
- _buildInsertDialog: function() {},
- _click: function() {},
- _getInsertDialogId: function() {},
- _getThumbnailSizes: function() {},
- _insertMedia: function() {},
- _insertMediaGallery: function() {},
- _insertMediaItem: function() {},
- _openInsertDialog: function() {},
- insertMedia: function() {},
- getMode: function() {},
- setupMediaElement: function() {},
- _dialogClose: function() {},
- _dialogInit: function() {},
- _dialogSetup: function() {},
- _dialogShow: function() {},
- _editMedia: function() {},
- _editorClose: function() {},
- _editorSuccess: function() {},
- _removeClipboardCheckboxes: function() {},
- _setMedia: function() {},
- addMedia: function() {},
- clipboardInsertMedia: function() {},
- getDialog: function() {},
- getOption: function() {},
- removeMedia: function() {},
- resetMedia: function() {},
- setMedia: function() {}
- };
- return Fake;
- }
-
- /**
- * @constructor
- */
- function MediaManagerEditor(options) {
- options = Core.extend({
- callbackInsert: null
- }, options);
-
- MediaManagerBase.call(this, options);
-
- this._forceClipboard = true;
- this._activeButton = null;
- var context = (this._options.editor) ? this._options.editor.core.toolbar()[0] : undefined;
- this._buttons = elByClass(this._options.buttonClass || 'jsMediaEditorButton', context);
- for (var i = 0, length = this._buttons.length; i < length; i++) {
- this._buttons[i].addEventListener(WCF_CLICK_EVENT, this._click.bind(this));
- }
- this._mediaToInsert = new Dictionary();
- this._mediaToInsertByClipboard = false;
- this._uploadData = null;
- this._uploadId = null;
-
- if (this._options.editor && !this._options.editor.opts.woltlab.attachments) {
- var editorId = elData(this._options.editor.$editor[0], 'element-id');
-
- var uuid1 = EventHandler.add('com.woltlab.wcf.redactor2', 'dragAndDrop_' + editorId, this._editorUpload.bind(this));
- var uuid2 = EventHandler.add('com.woltlab.wcf.redactor2', 'pasteFromClipboard_' + editorId, this._editorUpload.bind(this));
-
- EventHandler.add('com.woltlab.wcf.redactor2', 'destory_' + editorId, function() {
- EventHandler.remove('com.woltlab.wcf.redactor2', 'dragAndDrop_' + editorId, uuid1);
- EventHandler.remove('com.woltlab.wcf.redactor2', 'dragAndDrop_' + editorId, uuid2);
- });
-
- EventHandler.add('com.woltlab.wcf.media.upload', 'success', this._mediaUploaded.bind(this));
- }
- }
- Core.inherit(MediaManagerEditor, MediaManagerBase, {
- /**
- * @see WoltLabSuite/Core/Media/Manager/Base#_addButtonEventListeners
- */
- _addButtonEventListeners: function() {
- MediaManagerEditor._super.prototype._addButtonEventListeners.call(this);
-
- if (!this._mediaManagerMediaList) return;
-
- var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI');
- for (var i = 0, length = listItems.length; i < length; i++) {
- var listItem = listItems[i];
-
- var insertIcon = elByClass('jsMediaInsertButton', listItem)[0];
- if (insertIcon) {
- insertIcon.classList.remove('jsMediaInsertButton');
- insertIcon.addEventListener(WCF_CLICK_EVENT, this._openInsertDialog.bind(this));
- }
- }
- },
-
- /**
- * Builds the dialog to setup inserting media files.
- */
- _buildInsertDialog: function() {
- var thumbnailOptions = '';
-
- var thumbnailSizes = this._getThumbnailSizes();
- for (var i = 0, length = thumbnailSizes.length; i < length; i++) {
- thumbnailOptions += '<option value="' + thumbnailSizes[i] + '">' + Language.get('wcf.media.insert.imageSize.' + thumbnailSizes[i]) + '</option>';
- }
- thumbnailOptions += '<option value="original">' + Language.get('wcf.media.insert.imageSize.original') + '</option>';
-
- var dialog = '<div class="section">'
- /*+ (this._mediaToInsert.size > 1 ? '<dl>'
- + '<dt>' + Language.get('wcf.media.insert.type') + '</dt>'
- + '<dd>'
- + '<select name="insertType">'
- + '<option value="separate">' + Language.get('wcf.media.insert.type.separate') + '</option>'
- + '<option value="gallery">' + Language.get('wcf.media.insert.type.gallery') + '</option>'
- + '</select>'
- + '</dd>'
- + '</dl>' : '')*/
- + '<dl class="thumbnailSizeSelection">'
- + '<dt>' + Language.get('wcf.media.insert.imageSize') + '</dt>'
- + '<dd>'
- + '<select name="thumbnailSize">'
- + thumbnailOptions
- + '</select>'
- + '</dd>'
- + '</dl>'
- + '</div>'
- + '<div class="formSubmit">'
- + '<button class="buttonPrimary">' + Language.get('wcf.global.button.insert') + '</button>'
- + '</div>';
-
- UiDialog.open({
- _dialogSetup: (function() {
- return {
- id: this._getInsertDialogId(),
- options: {
- onClose: this._editorClose.bind(this),
- onSetup: function(content) {
- elByClass('buttonPrimary', content)[0].addEventListener(WCF_CLICK_EVENT, this._insertMedia.bind(this));
-
- // toggle thumbnail size selection based on selected insert type
- /*var insertType = elBySel('select[name=insertType]', content);
- if (insertType !== null) {
- var thumbnailSelection = elByClass('thumbnailSizeSelection', content)[0];
- insertType.addEventListener('change', function(event) {
- if (event.currentTarget.value === 'gallery') {
- elHide(thumbnailSelection);
- }
- else {
- elShow(thumbnailSelection);
- }
- });
- }*/
- var thumbnailSelection = elBySel('.thumbnailSizeSelection', content);
- elShow(thumbnailSelection);
- }.bind(this),
- title: Language.get('wcf.media.insert')
- },
- source: dialog
- };
- }).bind(this)
- });
- },
-
- /**
- * @see WoltLabSuite/Core/Media/Manager/Base#_click
- */
- _click: function(event) {
- this._activeButton = event.currentTarget;
-
- MediaManagerEditor._super.prototype._click.call(this, event);
- },
-
- /**
- * @see WoltLabSuite/Core/Media/Manager/Base#_dialogShow
- */
- _dialogShow: function() {
- MediaManagerEditor._super.prototype._dialogShow.call(this);
-
- // check if data needs to be uploaded
- if (this._uploadData) {
- if (this._uploadData.file) {
- this._upload.uploadFile(this._uploadData.file);
- }
- else {
- this._uploadId = this._upload.uploadBlob(this._uploadData.blob);
- }
-
- this._uploadData = null;
- }
- },
-
- /**
- * Handles pasting and dragging and dropping files into the editor.
- *
- * @param {object} data data of the uploaded file
- */
- _editorUpload: function(data) {
- this._uploadData = data;
-
- UiDialog.open(this);
- },
-
- /**
- * Returns the id of the insert dialog based on the media files to be inserted.
- *
- * @return {string} insert dialog id
- */
- _getInsertDialogId: function() {
- var dialogId = this._id + 'Insert';
-
- this._mediaToInsert.forEach(function(media, mediaId) {
- dialogId += '-' + mediaId;
- });
-
- return dialogId;
- },
-
- /**
- * Returns the supported thumbnail sizes (excluding `original`) for all media images to be inserted.
- *
- * @return {string[]}
- */
- _getThumbnailSizes: function() {
- var sizes = [];
-
- var supportedSizes = ['small', 'medium', 'large'];
- var size, supportSize;
- for (var i = 0, length = supportedSizes.length; i < length; i++) {
- size = supportedSizes[i];
-
- supportSize = true;
- this._mediaToInsert.forEach(function(media) {
- if (!media[size + 'ThumbnailType']) {
- supportSize = false;
- }
- });
-
- if (supportSize) {
- sizes.push(size);
- }
- }
-
- return sizes;
- },
-
- /**
- * Inserts media files into redactor.
- *
- * @param {Event?} event
- * @param {string?} thumbnailSize
- * @param {boolean?} closeEditor
- */
- _insertMedia: function(event, thumbnailSize, closeEditor) {
- if (closeEditor === undefined) closeEditor = true;
-
- var insertType = 'separate';
-
- // update insert options with selected values if method is called by clicking on 'insert' button
- // in dialog
- if (event) {
- UiDialog.close(this._getInsertDialogId());
-
- var dialogContent = event.currentTarget.closest('.dialogContent');
-
- /*if (this._mediaToInsert.size > 1) {
- insertType = elBySel('select[name=insertType]', dialogContent).value;
- }*/
- thumbnailSize = elBySel('select[name=thumbnailSize]', dialogContent).value;
- }
-
- if (this._options.callbackInsert !== null) {
- this._options.callbackInsert(this._mediaToInsert, insertType, thumbnailSize);
- }
- else {
- if (insertType === 'separate') {
- this._options.editor.buffer.set();
-
- this._mediaToInsert.forEach(this._insertMediaItem.bind(this, thumbnailSize));
- }
- else {
- this._insertMediaGallery();
- }
- }
-
- if (this._mediaToInsertByClipboard) {
- var mediaIds = [];
- this._mediaToInsert.forEach(function(media) {
- mediaIds.push(media.mediaID);
- });
-
- ControllerClipboard.unmark('com.woltlab.wcf.media', mediaIds);
- }
-
- this._mediaToInsert = new Dictionary();
- this._mediaToInsertByClipboard = false;
-
- // close manager dialog
- if (closeEditor) {
- UiDialog.close(this);
- }
- },
-
- /**
- * Inserts a series of uploaded images using a slider.
- *
- * @protected
- */
- _insertMediaGallery: function() {
- var mediaIds = [];
- this._mediaToInsert.forEach(function(item) {
- mediaIds.push(item.mediaID);
- });
-
- this._options.editor.buffer.set();
- this._options.editor.insert.text("[wsmg='" + mediaIds.join(',') + "'][/wsmg]");
- },
-
- /**
- * Inserts a single media item.
- *
- * @param {string} thumbnailSize preferred image dimension, is ignored for non-images
- * @param {Object} item media item data
- * @protected
- */
- _insertMediaItem: function(thumbnailSize, item) {
- if (item.isImage) {
- var sizes = ['small', 'medium', 'large', 'original'];
-
- // check if size is actually available
- var available = '', size;
- for (var i = 0; i < 4; i++) {
- size = sizes[i];
-
- if (item[size + 'ThumbnailHeight'] != 0) {
- available = size;
-
- if (thumbnailSize == size) {
- break;
- }
- }
- }
-
- thumbnailSize = available;
-
- if (!thumbnailSize) thumbnailSize = 'original';
-
- var link = item.link;
- if (thumbnailSize !== 'original') {
- link = item[thumbnailSize + 'ThumbnailLink'];
- }
-
- this._options.editor.insert.html('<img src="' + link + '" class="woltlabSuiteMedia" data-media-id="' + item.mediaID + '" data-media-size="' + thumbnailSize + '">');
- }
- else {
- this._options.editor.insert.text("[wsm='" + item.mediaID + "'][/wsm]");
- }
- },
-
- /**
- * Is called after media files are successfully uploaded to insert copied media.
- *
- * @param {object} data upload data
- */
- _mediaUploaded: function(data) {
- if (this._uploadId !== null && this._upload === data.upload) {
- if (this._uploadId === data.uploadId || (Array.isArray(this._uploadId) && this._uploadId.indexOf(data.uploadId) !== -1)) {
- this._mediaToInsert = Dictionary.fromObject(data.media);
- this._insertMedia(null, 'medium', false);
-
- this._uploadId = null;
- }
- }
- },
-
- /**
- * Handles clicking on the insert button.
- *
- * @param {Event} event insert button click event
- */
- _openInsertDialog: function(event) {
- this.insertMedia([~~elData(event.currentTarget, 'object-id')]);
- },
-
- /**
- * Is called to insert the media files with the given ids into an editor.
- *
- * @param {int[]} mediaIds
- */
- clipboardInsertMedia: function(mediaIds) {
- this.insertMedia(mediaIds, true);
- },
-
- /**
- * Prepares insertion of the media files with the given ids.
- *
- * @param {array<int>} mediaIds ids of the media files to be inserted
- * @param {boolean?} insertedByClipboard is true if the media files are inserted by clipboard
- */
- insertMedia: function(mediaIds, insertedByClipboard) {
- this._mediaToInsert = new Dictionary();
- this._mediaToInsertByClipboard = insertedByClipboard || false;
-
- // open the insert dialog if all media files are images
- var imagesOnly = true, media;
- for (var i = 0, length = mediaIds.length; i < length; i++) {
- media = this._media.get(mediaIds[i]);
- this._mediaToInsert.set(media.mediaID, media);
-
- if (!media.isImage) {
- imagesOnly = false;
- }
- }
-
- if (imagesOnly) {
- var thumbnailSizes = this._getThumbnailSizes();
- if (thumbnailSizes.length) {
- UiDialog.close(this);
- var dialogId = this._getInsertDialogId();
- if (UiDialog.getDialog(dialogId)) {
- UiDialog.openStatic(dialogId);
- }
- else {
- this._buildInsertDialog();
- }
- }
- else {
- this._insertMedia(undefined, 'original');
- }
- }
- else {
- this._insertMedia();
- }
- },
-
- /**
- * @see WoltLabSuite/Core/Media/Manager/Base#getMode
- */
- getMode: function() {
- return 'editor';
- },
-
- /**
- * @see WoltLabSuite/Core/Media/Manager/Base#setupMediaElement
- */
- setupMediaElement: function(media, mediaElement) {
- MediaManagerEditor._super.prototype.setupMediaElement.call(this, media, mediaElement);
-
- // add media insertion icon
- var buttons = elBySel('nav.buttonGroupNavigation > ul', mediaElement);
-
- var listItem = elCreate('li');
- listItem.className = 'jsMediaInsertButton';
- elData(listItem, 'object-id', media.mediaID);
- buttons.appendChild(listItem);
-
- listItem.innerHTML = '<a><span class="icon icon16 fa-plus jsTooltip" title="' + Language.get('wcf.media.button.insert') + '"></span> <span class="invisible">' + Language.get('wcf.media.button.insert') + '</span></a>';
- }
- });
-
- return MediaManagerEditor;
+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) {
+ "use strict";
+ Base_1 = tslib_1.__importDefault(Base_1);
+ Core = tslib_1.__importStar(Core);
+ EventHandler = tslib_1.__importStar(EventHandler);
+ DomTraverse = tslib_1.__importStar(DomTraverse);
+ Language = tslib_1.__importStar(Language);
+ UiDialog = tslib_1.__importStar(UiDialog);
+ Clipboard = tslib_1.__importStar(Clipboard);
+ Util_1 = tslib_1.__importDefault(Util_1);
+ class MediaManagerEditor extends Base_1.default {
+ constructor(options) {
+ options = Core.extend({
+ callbackInsert: null,
+ }, options);
+ super(options);
+ this._forceClipboard = true;
+ this._activeButton = null;
+ const context = this._options.editor ? this._options.editor.core.toolbar()[0] : undefined;
+ this._buttons = (context || window.document).getElementsByClassName(this._options.buttonClass || "jsMediaEditorButton");
+ Array.from(this._buttons).forEach((button) => {
+ button.addEventListener("click", (ev) => this._click(ev));
+ });
+ this._mediaToInsert = new Map();
+ this._mediaToInsertByClipboard = false;
+ this._uploadData = null;
+ this._uploadId = null;
+ if (this._options.editor && !this._options.editor.opts.woltlab.attachments) {
+ const editorId = this._options.editor.$editor[0].dataset.elementId;
+ const uuid1 = EventHandler.add("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, (data) => this._editorUpload(data));
+ const uuid2 = EventHandler.add("com.woltlab.wcf.redactor2", `pasteFromClipboard_${editorId}`, (data) => this._editorUpload(data));
+ EventHandler.add("com.woltlab.wcf.redactor2", `destroy_${editorId}`, () => {
+ EventHandler.remove("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, uuid1);
+ EventHandler.remove("com.woltlab.wcf.redactor2", `dragAndDrop_${editorId}`, uuid2);
+ });
+ EventHandler.add("com.woltlab.wcf.media.upload", "success", (data) => this._mediaUploaded(data));
+ }
+ }
+ _addButtonEventListeners() {
+ super._addButtonEventListeners();
+ if (!this._mediaManagerMediaList) {
+ return;
+ }
+ DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => {
+ const insertIcon = listItem.querySelector(".jsMediaInsertButton");
+ if (insertIcon) {
+ insertIcon.classList.remove("jsMediaInsertButton");
+ insertIcon.addEventListener("click", (ev) => this._openInsertDialog(ev));
+ }
+ });
+ }
+ /**
+ * Builds the dialog to setup inserting media files.
+ */
+ _buildInsertDialog() {
+ let thumbnailOptions = "";
+ this._getThumbnailSizes().forEach((thumbnailSize) => {
+ thumbnailOptions +=
+ '<option value="' +
+ thumbnailSize +
+ '">' +
+ Language.get("wcf.media.insert.imageSize." + thumbnailSize) +
+ "</option>";
+ });
+ thumbnailOptions += '<option value="original">' + Language.get("wcf.media.insert.imageSize.original") + "</option>";
+ const dialog = `
+ <div class="section">
+ <dl class="thumbnailSizeSelection">
+ <dt>${Language.get("wcf.media.insert.imageSize")}</dt>
+ <dd>
+ <select name="thumbnailSize">
+ ${thumbnailOptions}
+ </select>
+ </dd>
+ </dl>
+ </div>
+ <div class="formSubmit">
+ <button class="buttonPrimary">${Language.get("wcf.global.button.insert")}</button>
+ </div>`;
+ UiDialog.open({
+ _dialogSetup: () => {
+ return {
+ id: this._getInsertDialogId(),
+ options: {
+ onClose: () => this._editorClose(),
+ onSetup: (content) => {
+ content.querySelector(".buttonPrimary").addEventListener("click", (ev) => this._insertMedia(ev));
+ Util_1.default.show(content.querySelector(".thumbnailSizeSelection"));
+ },
+ title: Language.get("wcf.media.insert"),
+ },
+ source: dialog,
+ };
+ },
+ });
+ }
+ _click(event) {
+ this._activeButton = event.currentTarget;
+ super._click(event);
+ }
+ _dialogShow() {
+ super._dialogShow();
+ // check if data needs to be uploaded
+ if (this._uploadData) {
+ const fileUploadData = this._uploadData;
+ if (fileUploadData.file) {
+ this._upload.uploadFile(fileUploadData.file);
+ }
+ else {
+ const blobUploadData = this._uploadData;
+ this._uploadId = this._upload.uploadBlob(blobUploadData.blob);
+ }
+ this._uploadData = null;
+ }
+ }
+ /**
+ * Handles pasting and dragging and dropping files into the editor.
+ */
+ _editorUpload(data) {
+ this._uploadData = data;
+ UiDialog.open(this);
+ }
+ /**
+ * Returns the id of the insert dialog based on the media files to be inserted.
+ */
+ _getInsertDialogId() {
- return ["mediaInsert", ...this._mediaToInsert.keys()].join("-");
++ return [this._id + "Insert", ...this._mediaToInsert.keys()].join("-");
+ }
+ /**
+ * Returns the supported thumbnail sizes (excluding `original`) for all media images to be inserted.
+ */
+ _getThumbnailSizes() {
+ return ["small", "medium", "large"]
+ .map((size) => {
+ const sizeSupported = Array.from(this._mediaToInsert.values()).every((media) => {
+ return media[size + "ThumbnailType"] !== null;
+ });
+ if (sizeSupported) {
+ return size;
+ }
+ return null;
+ })
+ .filter((s) => s !== null);
+ }
+ /**
+ * Inserts media files into the editor.
+ */
+ _insertMedia(event, thumbnailSize, closeEditor = false) {
+ if (closeEditor === undefined)
+ closeEditor = true;
+ // update insert options with selected values if method is called by clicking on 'insert' button
+ // in dialog
+ if (event) {
+ UiDialog.close(this._getInsertDialogId());
+ const dialogContent = event.currentTarget.closest(".dialogContent");
+ const thumbnailSizeSelect = dialogContent.querySelector("select[name=thumbnailSize]");
+ thumbnailSize = thumbnailSizeSelect.value;
+ }
+ if (this._options.callbackInsert !== null) {
+ this._options.callbackInsert(this._mediaToInsert, "separate" /* Separate */, thumbnailSize);
+ }
+ else {
+ this._options.editor.buffer.set();
+ this._mediaToInsert.forEach((media) => this._insertMediaItem(thumbnailSize, media));
+ }
+ if (this._mediaToInsertByClipboard) {
+ Clipboard.unmark("com.woltlab.wcf.media", Array.from(this._mediaToInsert.keys()));
+ }
+ this._mediaToInsert = new Map();
+ this._mediaToInsertByClipboard = false;
+ // close manager dialog
+ if (closeEditor) {
+ UiDialog.close(this);
+ }
+ }
+ /**
+ * Inserts a single media item into the editor.
+ */
+ _insertMediaItem(thumbnailSize, media) {
+ if (media.isImage) {
+ let available = "";
+ ["small", "medium", "large", "original"].some((size) => {
+ if (media[size + "ThumbnailHeight"] != 0) {
+ available = size;
+ if (thumbnailSize == size) {
+ return true;
+ }
+ }
+ return false;
+ });
+ thumbnailSize = available;
+ if (!thumbnailSize) {
+ thumbnailSize = "original";
+ }
+ let link = media.link;
+ if (thumbnailSize !== "original") {
+ link = media[thumbnailSize + "ThumbnailLink"];
+ }
+ this._options.editor.insert.html(`<img src="${link}" class="woltlabSuiteMedia" data-media-id="${media.mediaID}" data-media-size="${thumbnailSize}">`);
+ }
+ else {
+ this._options.editor.insert.text(`[wsm='${media.mediaID}'][/wsm]`);
+ }
+ }
+ /**
+ * Is called after media files are successfully uploaded to insert copied media.
+ */
+ _mediaUploaded(data) {
+ if (this._uploadId !== null && this._upload === data.upload) {
+ if (this._uploadId === data.uploadId ||
+ (Array.isArray(this._uploadId) && this._uploadId.indexOf(data.uploadId) !== -1)) {
+ this._mediaToInsert = new Map(data.media.entries());
+ this._insertMedia(null, "medium", false);
+ this._uploadId = null;
+ }
+ }
+ }
+ /**
+ * Handles clicking on the insert button.
+ */
+ _openInsertDialog(event) {
+ const target = event.currentTarget;
+ this.insertMedia([~~target.dataset.objectId]);
+ }
+ /**
+ * Is called to insert the media files with the given ids into an editor.
+ */
+ clipboardInsertMedia(mediaIds) {
+ this.insertMedia(mediaIds, true);
+ }
+ /**
+ * Prepares insertion of the media files with the given ids.
+ */
+ insertMedia(mediaIds, insertedByClipboard) {
+ this._mediaToInsert = new Map();
+ this._mediaToInsertByClipboard = insertedByClipboard || false;
+ // open the insert dialog if all media files are images
+ let imagesOnly = true;
+ mediaIds.forEach((mediaId) => {
+ const media = this._media.get(mediaId);
+ this._mediaToInsert.set(media.mediaID, media);
+ if (!media.isImage) {
+ imagesOnly = false;
+ }
+ });
+ if (imagesOnly) {
+ const thumbnailSizes = this._getThumbnailSizes();
+ if (thumbnailSizes.length) {
+ UiDialog.close(this);
+ const dialogId = this._getInsertDialogId();
+ if (UiDialog.getDialog(dialogId)) {
+ UiDialog.openStatic(dialogId, null);
+ }
+ else {
+ this._buildInsertDialog();
+ }
+ }
+ else {
+ this._insertMedia(undefined, "original");
+ }
+ }
+ else {
+ this._insertMedia();
+ }
+ }
+ getMode() {
+ return "editor";
+ }
+ setupMediaElement(media, mediaElement) {
+ super.setupMediaElement(media, mediaElement);
+ // add media insertion icon
+ const buttons = mediaElement.querySelector("nav.buttonGroupNavigation > ul");
+ const listItem = document.createElement("li");
+ listItem.className = "jsMediaInsertButton";
+ listItem.dataset.objectId = media.mediaID.toString();
+ buttons.appendChild(listItem);
+ listItem.innerHTML = `
+ <a>
+ <span class="icon icon16 fa-plus jsTooltip" title="${Language.get("wcf.global.button.insert")}"></span>
+ <span class="invisible">${Language.get("wcf.global.button.insert")}</span>
+ </a>`;
+ }
+ }
+ Core.enableLegacyInheritance(MediaManagerEditor);
+ return MediaManagerEditor;
});