From ea3185a009ff755990aeb5db9c87c5d9c17916e1 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Mon, 25 May 2015 08:40:36 +0200 Subject: [PATCH] Add clipboard support for tags --- CHANGELOG.md | 1 + com.woltlab.wcf/clipboardAction.xml | 27 ++++-- com.woltlab.wcf/objectType.xml | 7 ++ wcfsetup/install/files/acp/js/WCF.ACP.js | 90 +++++++++++++++++++ .../install/files/acp/templates/tagList.tpl | 22 +++-- .../install/files/acp/templates/userList.tpl | 2 +- .../files/lib/acp/page/TagListPage.class.php | 2 + .../files/lib/data/tag/TagAction.class.php | 71 +++++++++++++++ .../files/lib/data/tag/TagEditor.class.php | 2 +- wcfsetup/install/lang/de.xml | 15 +++- wcfsetup/install/lang/en.xml | 15 +++- 11 files changed, 233 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb56b9054..a0db772df3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### 2.2.0 Alpha 1 (XXXX-YY-ZZ) +* Clipboard support for tags in ACP ("delete" and "set as synonyms"). * `wcf\data\user\UserProfileCache` for caching user profiles during runtime. * instruction file name for most PIPs has default value provided by `wcf\system\package\plugin\IPackageInstallationPlugin::getDefaultFilename()`. * `options` support for cronjobs. diff --git a/com.woltlab.wcf/clipboardAction.xml b/com.woltlab.wcf/clipboardAction.xml index 2addad9f27..c91192b202 100644 --- a/com.woltlab.wcf/clipboardAction.xml +++ b/com.woltlab.wcf/clipboardAction.xml @@ -1,6 +1,7 @@ + 1 @@ -8,7 +9,6 @@ - 2 @@ -16,7 +16,6 @@ - 3 @@ -24,7 +23,6 @@ - 4 @@ -32,7 +30,6 @@ - 5 @@ -40,7 +37,6 @@ - 6 @@ -48,7 +44,6 @@ - 7 @@ -56,7 +51,6 @@ - 8 @@ -64,7 +58,6 @@ - 9 @@ -72,5 +65,23 @@ + + + + + + 1 + + + + + + + 2 + + + + + diff --git a/com.woltlab.wcf/objectType.xml b/com.woltlab.wcf/objectType.xml index 83d5c75f2d..0b2ef40b9c 100644 --- a/com.woltlab.wcf/objectType.xml +++ b/com.woltlab.wcf/objectType.xml @@ -1,11 +1,18 @@ + com.woltlab.wcf.user com.woltlab.wcf.clipboardItem + + com.woltlab.wcf.tag + com.woltlab.wcf.clipboardItem + + + com.woltlab.wcf.collapsibleSidebar diff --git a/wcfsetup/install/files/acp/js/WCF.ACP.js b/wcfsetup/install/files/acp/js/WCF.ACP.js index a1224ef240..6f70b2674e 100644 --- a/wcfsetup/install/files/acp/js/WCF.ACP.js +++ b/wcfsetup/install/files/acp/js/WCF.ACP.js @@ -2754,3 +2754,93 @@ WCF.ACP.Ad.LocationHandler = Class.extend({ } } }); + +/** + * Initialize WCF.ACP.Tag namespace. + */ +WCF.ACP.Tag = { }; + +/** + * Handles setting tags as synonyms of another tag by clipboard. + */ +WCF.ACP.Tag.SetAsSynonymsHandler = Class.extend({ + /** + * dialog to select the "main" tag + * @var jQuery + */ + _dialog: null, + + /** + * ids of the selected tags + * @var array + */ + _objectIDs: [ ], + + /** + * Initializes the SetAsSynonymsHandler object. + * + * @param array objectIDs + */ + init: function() { + // bind listener + $('.jsClipboardEditor').each($.proxy(function(index, container) { + var $container = $(container); + var $types = eval($container.data('types')); + if (WCF.inArray('com.woltlab.wcf.tag', $types)) { + $container.on('clipboardAction', $.proxy(this._execute, this)); + return false; + } + }, this)); + }, + + /** + * Handles clipboard actions. + * + * @param object event + * @param string type + * @param string actionName + * @param object parameters + */ + _execute: function(event, type, actionName, parameters) { + if (type !== 'com.woltlab.wcf.tag' || actionName !== 'com.woltlab.wcf.tag.setAsSynonyms') { + return; + } + + this._objectIDs = parameters.objectIDs; + if (this._dialog === null) { + this._dialog = $('
').hide().appendTo(document.body); + this._dialog.wcfDialog({ + closable: false, + title: WCF.Language.get('wcf.acp.tag.setAsSynonyms') + }); + } + + this._dialog.html(parameters.template); + $button = this._dialog.find('button[data-type="submit"]').disable().click($.proxy(this._submit, this)); + this._dialog.find('input[type=radio]').change(function() { $button.enable(); }); + }, + + /** + * Saves the tags as synonyms. + */ + _submit: function() { + new WCF.Action.Proxy({ + autoSend: true, + data: { + actionName: 'setAsSynonyms', + className: 'wcf\\data\\tag\\TagAction', + objectIDs: this._objectIDs, + parameters: { + tagID: this._dialog.find('input[name="tagID"]:checked').val() + } + }, + success: $.proxy(function() { + this._dialog.wcfDialog('close'); + + new WCF.System.Notification().show(function() { + window.location.reload(); + }); + }, this) + }); + } +}); diff --git a/wcfsetup/install/files/acp/templates/tagList.tpl b/wcfsetup/install/files/acp/templates/tagList.tpl index a92742f903..f6620eb8d0 100644 --- a/wcfsetup/install/files/acp/templates/tagList.tpl +++ b/wcfsetup/install/files/acp/templates/tagList.tpl @@ -3,7 +3,15 @@ @@ -43,7 +51,7 @@ @@ -55,9 +63,10 @@

{lang}wcf.acp.tag.list{/lang} {#$items}

- +
+ @@ -70,7 +79,8 @@ {foreach from=$objects item=tag} - + +
{lang}wcf.global.objectID{/lang} {lang}wcf.acp.tag.name{/lang} {lang}wcf.acp.tag.usageCount{/lang}
@@ -97,10 +107,12 @@ + + {else}

{lang}wcf.global.noItems{/lang}

diff --git a/wcfsetup/install/files/acp/templates/userList.tpl b/wcfsetup/install/files/acp/templates/userList.tpl index b829436717..5c147ac9c0 100644 --- a/wcfsetup/install/files/acp/templates/userList.tpl +++ b/wcfsetup/install/files/acp/templates/userList.tpl @@ -131,7 +131,7 @@
- +
{@$pagesLinks} diff --git a/wcfsetup/install/files/lib/acp/page/TagListPage.class.php b/wcfsetup/install/files/lib/acp/page/TagListPage.class.php index f404c918f5..0e9a581bee 100644 --- a/wcfsetup/install/files/lib/acp/page/TagListPage.class.php +++ b/wcfsetup/install/files/lib/acp/page/TagListPage.class.php @@ -1,6 +1,7 @@ assign(array( + 'hasMarkedItems' => ClipboardHandler::getInstance()->hasMarkedItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.tag')), 'search' => $this->search )); } diff --git a/wcfsetup/install/files/lib/data/tag/TagAction.class.php b/wcfsetup/install/files/lib/data/tag/TagAction.class.php index d1fb8ea791..43c61e23ec 100644 --- a/wcfsetup/install/files/lib/data/tag/TagAction.class.php +++ b/wcfsetup/install/files/lib/data/tag/TagAction.class.php @@ -2,6 +2,7 @@ namespace wcf\data\tag; use wcf\data\AbstractDatabaseObjectAction; use wcf\data\ISearchAction; +use wcf\system\clipboard\ClipboardHandler; use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\exception\UserInputException; use wcf\system\WCF; @@ -42,6 +43,12 @@ class TagAction extends AbstractDatabaseObjectAction implements ISearchAction { */ protected $requireACP = array('delete', 'update'); + /** + * tag for which other tags will be used as synonyms + * @var \wcf\data\tag\TagEditor + */ + public $tagEditor = null; + /** * @see \wcf\data\ISearchAction::validateGetSearchResultList() */ @@ -84,4 +91,68 @@ class TagAction extends AbstractDatabaseObjectAction implements ISearchAction { return $list; } + + /** + * @see \wcf\data\IDeleteAction::delete() + */ + public function delete() { + $returnValue = parent::delete(); + + $this->unmarkItems(); + + return $returnValue; + } + + /** + * Validates the 'setAsSynonyms' action. + */ + public function validateSetAsSynonyms() { + WCF::getSession()->checkPermissions([ 'admin.content.tag.canManageTag' ]); + if (empty($this->objects)) { + $this->readObjects(); + + if (count($this->objects) < 2) { + throw new UserInputException('objectIDs'); + } + } + + $this->readInteger('tagID'); + $this->tagEditor = new TagEditor(new Tag($this->parameters['tagID'])); + if (!$this->tagEditor->tagID) { + throw new UserInputException('tagID'); + } + } + + /** + * Sets a number of tags as a synonyms of another tag. + */ + public function setAsSynonyms() { + // the "main" tag may not be a synonym itself + if ($this->tagEditor->synonymFor) { + $this->tagEditor->update([ + 'synonymFor' => null + ]); + } + + foreach ($this->objects as $tagEditor) { + $this->tagEditor->addSynonym($tagEditor->getDecoratedObject()); + } + + $this->unmarkItems(); + } + + /** + * Unmarks tags. + * + * @param array $tagIDs + */ + protected function unmarkItems(array $tagIDs = array()) { + if (empty($tagIDs)) { + $tagIDs = $this->objectIDs; + } + + if (!empty($tagIDs)) { + ClipboardHandler::getInstance()->unmark($tagIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.tag')); + } + } } diff --git a/wcfsetup/install/files/lib/data/tag/TagEditor.class.php b/wcfsetup/install/files/lib/data/tag/TagEditor.class.php index 4c3a9be330..64ccc4f065 100644 --- a/wcfsetup/install/files/lib/data/tag/TagEditor.class.php +++ b/wcfsetup/install/files/lib/data/tag/TagEditor.class.php @@ -26,7 +26,7 @@ class TagEditor extends DatabaseObjectEditor { */ public function addSynonym(Tag $synonym) { if ($synonym->tagID == $this->tagID) return; - + // assign all associations for the synonym with this tag $sql = "UPDATE IGNORE wcf".WCF_N."_tag_to_object SET tagID = ? diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 4a373f56d8..107fb5ddcb 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -1505,6 +1505,8 @@ GmbH=Gesellschaft mit beschränkter Haftung]]> + + @@ -1880,18 +1882,25 @@ Fehler sind beispielsweise: + + + + + + + + + + - - - diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 79f0214529..8422b42529 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -1504,6 +1504,8 @@ GmbH=Gesellschaft mit beschränkter Haftung]]> + + @@ -1879,18 +1881,25 @@ Errors are: + + + + + + + + + + - - - -- 2.20.1