<page>menuManagerDialog-select</page>
</pages>
</action>
+ <action name="setCategory">
+ <actionclassname>wcf\system\clipboard\action\MediaClipboardAction</actionclassname>
+ <showorder>3</showorder>
+ <pages>
+ <page>wcf\acp\page\MediaListPage</page>
+ <page>menuManagerDialog-editor</page>
+ <page>menuManagerDialog-select</page>
+ </pages>
+ </action>
<!-- /com.woltlab.wcf.media -->
<!-- com.woltlab.wcf.article -->
--- /dev/null
+<div class="section">
+ <dl>
+ <dt><label for="postCopyNewThreadTopic">{lang}wcf.media.category.choose{/lang}</label></dt>
+ <select name="categoryID">
+ <option value="0">{lang}wcf.global.noSelection{/lang}</option>
+
+ {foreach from=$categoryList item=categoryItem}
+ <option value="{$categoryItem->categoryID}">{$categoryItem->getTitle()}</option>
+
+ {if $categoryItem->hasChildren()}
+ {foreach from=$categoryItem item=subCategoryItem}
+ <option value="{$subCategoryItem->categoryID}"> {$subCategoryItem->getTitle()}</option>
+
+ {if $subCategoryItem->hasChildren()}
+ {foreach from=$subCategoryItem item=subSubCategoryItem}
+ <option value="{$subSubCategoryItem->categoryID}"> {$subSubCategoryItem->getTitle()}</option>
+ {/foreach}
+ {/if}
+ {/foreach}
+ {/if}
+ {/foreach}
+ </select>
+ </dl>
+</div>
+
+<div class="formSubmit">
+ <button data-type="submit" class="buttonPrimary">{lang}wcf.global.button.submit{/lang}</button>
+</div>
'wcf.media.search.noResults': '{lang}wcf.media.search.noResults{/lang}',
'wcf.media.upload.error.noImage': '{lang}wcf.media.upload.error.noImage{/lang}',
'wcf.media.upload.error.uploadFailed': '{lang}wcf.media.upload.error.uploadFailed{/lang}',
- 'wcf.media.upload.success': '{lang}wcf.media.upload.success{/lang}'
+ 'wcf.media.upload.success': '{lang}wcf.media.upload.success{/lang}',
+ 'wcf.media.setCategory': '{lang}wcf.media.setCategory{/lang}'
});
Permission.add('admin.content.cms.canManageMedia', {if $__wcf->session->getPermission('admin.content.cms.canManageMedia')}true{else}false{/if});
--- /dev/null
+<div class="section">
+ <dl>
+ <dt><label for="postCopyNewThreadTopic">{lang}wcf.media.category.choose{/lang}</label></dt>
+ <select name="categoryID">
+ <option value="0">{lang}wcf.global.noSelection{/lang}</option>
+
+ {foreach from=$categoryList item=categoryItem}
+ <option value="{$categoryItem->categoryID}">{$categoryItem->getTitle()}</option>
+
+ {if $categoryItem->hasChildren()}
+ {foreach from=$categoryItem item=subCategoryItem}
+ <option value="{$subCategoryItem->categoryID}"> {$subCategoryItem->getTitle()}</option>
+
+ {if $subCategoryItem->hasChildren()}
+ {foreach from=$subCategoryItem item=subSubCategoryItem}
+ <option value="{$subSubCategoryItem->categoryID}"> {$subSubCategoryItem->getTitle()}</option>
+ {/foreach}
+ {/if}
+ {/foreach}
+ {/if}
+ {/foreach}
+ </select>
+ </dl>
+</div>
+
+<div class="formSubmit">
+ <button data-type="submit" class="buttonPrimary">{lang}wcf.global.button.submit{/lang}</button>
+</div>
'wcf.media.search.noResults': '{lang}wcf.media.search.noResults{/lang}',
'wcf.media.upload.error.noImage': '{lang}wcf.media.upload.error.noImage{/lang}',
'wcf.media.upload.error.uploadFailed': '{lang}wcf.media.upload.error.uploadFailed{/lang}',
- 'wcf.media.upload.success': '{lang}wcf.media.upload.success{/lang}'
+ 'wcf.media.upload.success': '{lang}wcf.media.upload.success{/lang}',
+ 'wcf.media.setCategory': '{lang}wcf.media.setCategory{/lang}'
});
Permission.add('admin.content.cms.canManageMedia', {if $__wcf->session->getPermission('admin.content.cms.canManageMedia')}true{else}false{/if});
{include file='mediaJavaScript'}
require(['Language', 'WoltLabSuite/Core/Controller/Media/List'], function (Language, ControllerMediaList) {
- Language.add('wcf.media.delete.confirmMessage', '{lang __literal=true}wcf.media.delete.confirmMessage{/lang}')
+ Language.addObject({
+ 'wcf.media.delete.confirmMessage': '{lang __literal=true}wcf.media.delete.confirmMessage{/lang}',
+ 'wcf.media.setCategory': '{lang}wcf.media.setCategory{/lang}'
+ });
+
ControllerMediaList.init({
{if $categoryID}
categoryId: {@$categoryID},
'Dom/ChangeListener',
'EventHandler',
'WoltLabSuite/Core/Controller/Clipboard',
+ 'WoltLabSuite/Core/Media/Clipboard',
'WoltLabSuite/Core/Media/Editor',
'WoltLabSuite/Core/Media/List/Upload'
],
DomChangeListener,
EventHandler,
Clipboard,
+ MediaClipboard,
MediaEditor,
MediaListUpload
) {
var Fake = function() {};
Fake.prototype = {
init: function() {},
- _clipboardAction: function() {},
+ _addButtonEventListeners: function() {},
+ _deleteCallback: function() {},
+ _deleteMedia: function(mediaIds) {},
_edit: function() {}
};
return Fake;
var _mediaEditor;
var _tableBody = elById('mediaListTableBody');
+ var _clipboardObjectIds = [];
/**
* @exports WoltLabSuite/Core/Controller/Media/List
multiple: true
});
- Clipboard.setup({
- hasMarkedItems: options.hasMarkedItems || false,
- pageClassName: 'wcf\\acp\\page\\MediaListPage'
- });
+ MediaClipboard.init(
+ 'wcf\\acp\\page\\MediaListPage',
+ options.hasMarkedItems || false,
+ this
+ );
- EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.media', this._clipboardAction.bind(this));
EventHandler.add('com.woltlab.wcf.media.upload', 'removedErroneousUploadRow', this._deleteCallback.bind(this));
var deleteAction = new WCF.Action.Delete('wcf\\data\\media\\MediaAction', '.jsMediaRow');
},
/**
- * Handles successful clipboard actions.
+ * Is called when a media edit icon is clicked.
*
- * @param {object} actionData
+ * @param {Event} event
*/
- _clipboardAction: function(actionData) {
- // only consider events if the action has been executed
- if (actionData.responseData === null) {
- return;
- }
-
- if (actionData.data.actionName === 'com.woltlab.wcf.media.delete') {
- var mediaIds = actionData.responseData.objectIDs;
-
- var mediaRows = elByClass('jsMediaRow');
- for (var i = 0; i < mediaRows.length; i++) {
- var media = mediaRows[i];
- var mediaID = ~~elData(elByClass('jsClipboardItem', media)[0], 'object-id');
-
- if (mediaIds.indexOf(mediaID) !== -1) {
- elRemove(media);
- i--;
- }
- }
-
- if (!mediaRows.length) {
- window.location.reload();
- }
- }
+ _edit: function(event) {
+ _mediaEditor.edit(elData(event.currentTarget, 'object-id'));
},
/**
- * Is called when a media edit icon is clicked.
+ * Is called after the media files with the given ids have been deleted via clipboard.
*
- * @param {Event} event
+ * @param {int[]} mediaIds ids of deleted media files
*/
- _edit: function(event) {
- _mediaEditor.edit(elData(event.currentTarget, 'object-id'));
+ clipboardDeleteMedia: function(mediaIds) {
+ var mediaRows = elByClass('jsMediaRow');
+ for (var i = 0; i < mediaRows.length; i++) {
+ var media = mediaRows[i];
+ var mediaID = ~~elData(elByClass('jsClipboardItem', media)[0], 'object-id');
+
+ if (mediaIds.indexOf(mediaID) !== -1) {
+ elRemove(media);
+ i--;
+ }
+ }
+
+ if (!mediaRows.length) {
+ window.location.reload();
+ }
}
}
});
\ No newline at end of file
--- /dev/null
+/**
+ * Initializes modules required for media clipboard.
+ *
+ * @author Matthias Schmidt
+ * @copyright 2001-2018 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Media/Clipboard
+ */
+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 _mediaManager;
+
+ /**
+ * @exports WoltLabSuite/Core/Media/Clipboard
+ */
+ return {
+ init: function(pageClassName, hasMarkedItems, mediaManager) {
+ Clipboard.setup({
+ hasMarkedItems: hasMarkedItems,
+ pageClassName: pageClassName
+ });
+
+ _mediaManager = mediaManager;
+
+ EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.media', this._clipboardAction.bind(this));
+ },
+
+ /**
+ * 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
+ }
+ });
+ }
+ }
+});
\ No newline at end of file
'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/Ui/Pagination',
+ 'WoltLabSuite/Core/Media/Clipboard'
],
function(
Core, Dictionary, DomChangeListener, DomTraverse,
DomUtil, EventHandler, Language, List,
Permission, UiDialog, UiNotification, Clipboard,
MediaEditor, MediaUpload, MediaManagerSearch, StringUtil,
- UiPagination
+ UiPagination,
+ MediaClipboard
)
{
"use strict";
Fake.prototype = {
_addButtonEventListeners: function() {},
_click: function() {},
- _clipboardAction: function() {},
_dialogClose: function() {},
_dialogInit: function() {},
_dialogSetup: function() {},
_removeClipboardCheckboxes: function() {},
_setMedia: function() {},
addMedia: function() {},
+ clipboardDeleteMedia: function() {},
getDialog: function() {},
getMode: function() {},
getOption: function() {},
UiDialog.open(this);
},
- /**
- * Reacts to executed clipboard actions.
- *
- * @param {object<string, *>} actionData data of the executed clipboard action
- */
- _clipboardAction: function(actionData) {
- // only consider events if the action has been executed
- if (actionData.data.actionName === 'com.woltlab.wcf.media.delete' && actionData.responseData !== null) {
- var mediaIds = actionData.responseData.objectIDs;
- for (var i = 0, length = mediaIds.length; i < length; i++) {
- this.removeMedia(~~mediaIds[i], true);
- }
-
- UiNotification.show();
- }
- },
-
/**
* Is called if the media manager dialog is closed.
*/
}
if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) {
- EventHandler.add('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.media', this._clipboardAction.bind(this));
-
- Clipboard.setup({
- hasMarkedItems: this._hadInitiallyMarkedItems ? true : false,
- pageClassName: 'menuManagerDialog-' + this.getMode()
- });
+ MediaClipboard.init(
+ 'menuManagerDialog-' + this.getMode(),
+ this._hadInitiallyMarkedItems ? true : false,
+ this
+ );
}
else {
this._removeClipboardCheckboxes();
}
},
+ /**
+ * 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.
*
_addButtonEventListeners: function() {},
_buildInsertDialog: function() {},
_click: function() {},
- _clipboardAction: function() {},
_getInsertDialogId: function() {},
_getThumbnailSizes: function() {},
_insertMedia: function() {},
_removeClipboardCheckboxes: function() {},
_setMedia: function() {},
addMedia: function() {},
+ clipboardInsertMedia: function() {},
getDialog: function() {},
getOption: function() {},
removeMedia: function() {},
MediaManagerEditor._super.prototype._click.call(this, event);
},
- /**
- * @see WoltLabSuite/Core/Media/Manager/Base#_clipboardAction
- */
- _clipboardAction: function(actionData) {
- MediaManagerEditor._super.prototype._clipboardAction.call(this, actionData);
-
- if (actionData.data.actionName === 'com.woltlab.wcf.media.insert') {
- this.insertMedia(actionData.data.parameters.objectIDs, true);
- }
- },
-
/**
* @see WoltLabSuite/Core/Media/Manager/Base#_dialogShow
*/
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.
*
use wcf\system\category\CategoryHandler;
use wcf\system\clipboard\ClipboardHandler;
use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
use wcf\system\language\I18nHandler;
ClipboardHandler::getInstance()->unmark($mediaIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.media'));
}
}
+
+ /**
+ * Validates the `getSetCategoryDialog` action.
+ *
+ * @throws PermissionDeniedException if user is not allowed to set category of media files
+ * @throws IllegalLinkException if no media file categories exist
+ */
+ public function validateGetSetCategoryDialog() {
+ if (!WCF::getSession()->getPermission('admin.content.cms.canManageMedia')) {
+ throw new PermissionDeniedException();
+ }
+
+ if (empty(CategoryHandler::getInstance()->getCategories('com.woltlab.wcf.media.category'))) {
+ throw new IllegalLinkException();
+ }
+ }
+
+ /**
+ * Returns the dialog to set the category of multiple media files.
+ *
+ * @return string[]
+ */
+ public function getSetCategoryDialog() {
+ $categoryList = (new CategoryNodeTree('com.woltlab.wcf.media.category'))->getIterator();
+ $categoryList->setMaxDepth(0);
+
+ return [
+ 'template' => WCF::getTPL()->fetch('__mediaSetCategoryDialog', 'wcf', [
+ 'categoryList' => $categoryList
+ ])
+ ];
+ }
+
+ /**
+ * Validates the `setCategory` action.
+ *
+ * @throws UserInputException if no object ids are given
+ */
+ public function validateSetCategory() {
+ $this->validateGetSetCategoryDialog();
+
+ if (empty($this->objects)) {
+ $this->readObjects();
+
+ if (empty($this->objects)) {
+ throw new UserInputException('objectIDs');
+ }
+ }
+
+ $this->readInteger('categoryID', true);
+ }
+
+ /**
+ * Sets the category of multiple media files.
+ */
+ public function setCategory() {
+ $conditionBuilder = new PreparedStatementConditionBuilder();
+ $conditionBuilder->add('mediaID IN (?)', [$this->objectIDs]);
+
+ $sql = "UPDATE wcf" . WCF_N . "_media
+ SET categoryID = ?
+ " . $conditionBuilder;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array_merge(
+ [$this->parameters['categoryID'] ?: null],
+ $conditionBuilder->getParameters()
+ ));
+
+ $this->unmarkItems();
+ }
}
namespace wcf\system\clipboard\action;
use wcf\data\clipboard\action\ClipboardAction;
use wcf\data\media\MediaAction;
+use wcf\system\category\CategoryHandler;
use wcf\system\WCF;
/**
*/
protected $supportedActions = [
'delete',
- 'insert'
+ 'insert',
+ 'setCategory'
];
/**
public function validateInsert() {
return array_keys($this->objects);
}
+
+ /**
+ * Returns the ids of the media files whose category can be set.
+ *
+ * @return integer[]
+ */
+ public function validateSetCategory() {
+ if (!WCF::getSession()->getPermission('admin.content.cms.canManageMedia')) {
+ return [];
+ }
+
+ // category can only be set if any category exists
+ if (empty(CategoryHandler::getInstance()->getCategories('com.woltlab.wcf.media.category'))) {
+ return [];
+ }
+
+ return array_keys($this->objects);
+ }
}
<item name="wcf.clipboard.item.com.woltlab.wcf.media.delete"><![CDATA[Löschen ({#$count})]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.media.delete.confirmMessage"><![CDATA[{if $count == 1}Eine Datei{else}{#$count} Dateien{/if} löschen?]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.media.insert"><![CDATA[Einfügen ({#$count})]]></item>
-
+ <item name="wcf.clipboard.item.com.woltlab.wcf.media.setCategory"><![CDATA[Kategorie bearbeiten ({#$count})]]></item>
+
<item name="wcf.clipboard.item.com.woltlab.wcf.tag.delete"><![CDATA[Löschen ({#$count})]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.tag.delete.confirmMessage"><![CDATA[{if $count == 1}Einen Tag{else}{#$count} Tag{/if} löschen?]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.tag.setAsSynonyms"><![CDATA[Als Synonyme verwenden ({#$count})]]></item>
<item name="wcf.media.uploadTime"><![CDATA[Datum hochgeladen]]></item>
<item name="wcf.media.search.noResults"><![CDATA[Es wurden keine Ergebnisse gefunden.]]></item>
<item name="wcf.media.search.info.searchStringThreshold"><![CDATA[Der Suchbegriff muss mindestens {#$minSearchLength} Zeichen lang sein.]]></item>
+ <item name="wcf.media.setCategory"><![CDATA[Kategorie bearbeiten]]></item>
</category>
<category name="wcf.message">
<item name="wcf.clipboard.item.com.woltlab.wcf.media.delete"><![CDATA[Delete ({#$count})]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.media.delete.confirmMessage"><![CDATA[Do you really want to delete {#$count} file{if $count != 1}s{/if}?]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.media.insert"><![CDATA[Insert ({#$count})]]></item>
+ <item name="wcf.clipboard.item.com.woltlab.wcf.media.setCategory"><![CDATA[Edit Category ({#$count})]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.tag.delete"><![CDATA[Delete ({#$count})]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.tag.delete.confirmMessage"><![CDATA[Do you really want to delete {#$count} tag{if $count != 1}s{/if}?]]></item>
<item name="wcf.media.uploadTime"><![CDATA[Upload Date]]></item>
<item name="wcf.media.search.noResults"><![CDATA[The search returned no results.]]></item>
<item name="wcf.media.search.info.searchStringThreshold"><![CDATA[The search term must contain at least {#$minSearchLength} character{if $minSearchLength > 1}s{/if}.]]></item>
+ <item name="wcf.media.setCategory"><![CDATA[Edit Category]]></item>
</category>
<category name="wcf.message">