Added ability to sort attachments by drag&drop
authorAlexander Ebert <ebert@woltlab.com>
Thu, 22 May 2014 18:18:45 +0000 (20:18 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 22 May 2014 18:18:45 +0000 (20:18 +0200)
com.woltlab.wcf/templates/messageFormAttachments.tpl
wcfsetup/install/files/js/3rdParty/redactor/plugins/wupload.js
wcfsetup/install/files/js/WCF.Attachment.js
wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php

index 295386fa39e56984efcf8c86bdc2b0bbb62b05d0..9ca15aa3667338d2b0ebf68ace9428b649c75614 100644 (file)
@@ -1,7 +1,7 @@
 <div id="attachments" class="jsOnly formAttachmentContent tabMenuContent container containerPadding">
        <ul class="formAttachmentList clearfix"{if !$attachmentHandler->getAttachmentList()|count} style="display: none"{/if}>
                {foreach from=$attachmentHandler->getAttachmentList() item=$attachment}
-                       <li class="box48">
+                       <li class="box48" data-object-id="{@$attachment->attachmentID}">
                                {if $attachment->tinyThumbnailType}
                                        <img src="{link controller='Attachment' object=$attachment}tiny=1{/link}" alt="" class="attachmentTinyThumbnail" />
                                {else}
index 2ba974dcb0321b9bcbe705147177cbd44b8c0b9b..efb570b1e1e8a5e503f2e53f3e872903b9cd4078 100644 (file)
@@ -37,7 +37,7 @@ RedactorPlugins.wupload = {
                if ($options.attachments.length) {
                        for (var $i = 0; $i < $options.attachments.length; $i++) {
                                var $attachment = $options.attachments[$i];
-                               var $listItem = $('<li class="box48" />');
+                               var $listItem = $('<li class="box48" />').data('objectID', $attachment.attachmentID);
                                if ($attachment.tinyThumbnailUrl) {
                                        $('<img src="' + $attachment.tinyThumbnailUrl + '" alt="" class="attachmentTinyThumbnail" />').appendTo($listItem);
                                }
index 9b05e2862984753dd1a9b28fe44f19786e9bb8f2..1e8bbd84f0552b15b92de43b6cf7051d88e27d72 100644 (file)
@@ -55,6 +55,8 @@ WCF.Attachment.Upload = WCF.Upload.extend({
                this._fileListSelector.find('.jsButtonInsertAttachment').click($.proxy(this._insert, this));
                
                WCF.DOMNodeRemovedHandler.addCallback('WCF.Attachment.Upload', $.proxy(this._removeLimitError, this));
+               
+               this._makeSortable();
        },
        
        /**
@@ -200,6 +202,8 @@ WCF.Attachment.Upload = WCF.Upload.extend({
                                var $deleteButton = $('<li><span class="icon icon16 icon-remove pointer jsTooltip jsDeleteButton" title="'+WCF.Language.get('wcf.global.button.delete')+'" data-object-id="'+data.returnValues.attachments[$internalFileID]['attachmentID']+'" data-confirm-message="'+WCF.Language.get('wcf.attachment.delete.sure')+'" /></li>');
                                $li.find('ul').append($deleteButton);
                                
+                               $li.data('objectID', data.returnValues.attachments[$internalFileID].attachmentID);
+                               
                                if (this._wysiwygContainerID) {
                                        var $insertButton = $('<li><span class="icon icon16 icon-paste pointer jsTooltip jsButtonInsertAttachment" title="' + WCF.Language.get('wcf.attachment.insert') + '" data-object-id="' + data.returnValues.attachments[$internalFileID]['attachmentID'] + '" /></li>');
                                        $insertButton.children('.jsButtonInsertAttachment').click($.proxy(this._insert, this));
@@ -228,6 +232,8 @@ WCF.Attachment.Upload = WCF.Upload.extend({
                        $li.css('display', 'block');
                }
                
+               this._makeSortable();
+               
                WCF.DOMNodeInsertedHandler.execute();
        },
        
@@ -272,5 +278,50 @@ WCF.Attachment.Upload = WCF.Upload.extend({
                                $listItem.find('div > div').append($('<small class="innerError">' + (data.responseJSON && data.responseJSON.message ? data.responseJSON.message : WCF.Language.get('wcf.attachment.upload.error.uploadFailed')) + '</small>'));
                        }
                });
+       },
+       
+       /**
+        * Initializes sorting for uploaded attachments.
+        */
+       _makeSortable: function() {
+               var $attachments = this._fileListSelector.children('li:not(.uploadFailed)');
+               if (!$attachments.length) {
+                       return;
+               }
+               
+               $attachments.addClass('sortableAttachment').children('img').addClass('sortableNode');
+               
+               if (!this._fileListSelector.hasClass('sortableList')) {
+                       this._fileListSelector.addClass('sortableList');
+                       
+                       var self = this;
+                       new WCF.Sortable.List(this._fileListSelector.parent().wcfIdentify(), '', 0, {
+                               axis: false,
+                               items: 'li.sortableAttachment',
+                               toleranceElement: null,
+                               update: function(event, ui) {
+                                       var $attachmentIDs = [ ];
+                                       self._fileListSelector.children('li:not(.uploadFailed)').each(function(index, listItem) {
+                                               $attachmentIDs.push($(listItem).data('objectID'));
+                                       });
+                                       
+                                       if ($attachmentIDs.length) {
+                                               new WCF.Action.Proxy({
+                                                       autoSend: true,
+                                                       data: {
+                                                               actionName: 'updatePosition',
+                                                               className: 'wcf\\data\\attachment\\AttachmentAction',
+                                                               parameters: {
+                                                                       attachmentIDs: $attachmentIDs,
+                                                                       objectID: self._objectID,
+                                                                       objectType: self._objectType,
+                                                                       tmpHash: self._tmpHash
+                                                               }
+                                                       }
+                                               });
+                                       }
+                               }
+                       }, true);
+               }
        }
 });
index 6a2bae9e1a415aaec43d830d4c5ddab7a6c89b26..b5b5e4842203ad76cf82feff5f4a973055ea8c1d 100644 (file)
@@ -11,6 +11,8 @@ use wcf\system\request\LinkHandler;
 use wcf\system\upload\DefaultUploadFileValidationStrategy;
 use wcf\system\WCF;
 use wcf\util\FileUtil;
+use wcf\util\ArrayUtil;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
 
 /**
  * Executes attachment-related actions.
@@ -315,4 +317,84 @@ class AttachmentAction extends AbstractDatabaseObjectAction {
                        }
                }
        }
+       
+       /**
+        * Validates parameters to update the attachments show order.
+        */
+       public function validateUpdatePosition() {
+               $this->readInteger('objectID', true);
+               $this->readString('objectType');
+               $this->readString('tmpHash', true);
+               
+               if (empty($this->parameters['objectID']) && empty($this->parameters['tmpHash'])) {
+                       throw new UserInputException('objectID');
+               }
+               
+               // validate object type
+               $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.attachment.objectType', $this->parameters['objectType']);
+               if ($objectType === null) {
+                       throw new UserInputException('objectType');
+               }
+               
+               if (!empty($this->parameters['objectID'])) {
+                       // check upload permissions
+                       if (!$objectType->getProcessor()->canUpload($this->parameters['objectID'])) {
+                               throw new PermissionDeniedException();
+                       }
+               }
+               
+               if (!isset($this->parameters['attachmentIDs']) || !is_array($this->parameters['attachmentIDs'])) {
+                       throw new UserInputException('attachmentIDs');
+               }
+               
+               $this->parameters['attachmentIDs'] = ArrayUtil::toIntegerArray($this->parameters['attachmentIDs']);
+               
+               // check attachment ids
+               $attachmentIDs = array();
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("attachmentID IN (?)", array($this->parameters['attachmentIDs']));
+               $conditions->add("objectTypeID = ?", array($objectType->objectTypeID));
+               
+               if (!empty($this->parameters['objectID'])) {
+                       $conditions->add("objectID = ?", array($this->parameters['objectID']));
+               }
+               else {
+                       $conditions->add("tmpHash = ?", array($this->parameters['tmpHash']));
+               }
+               
+               $sql = "SELECT  attachmentID
+                       FROM    wcf".WCF_N."_attachment
+                       ".$conditions;
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute($conditions->getParameters());
+               while ($row = $statement->fetchArray()) {
+                       $attachmentIDs[] = $row['attachmentID'];
+               }
+               
+               foreach ($this->parameters['attachmentIDs'] as $attachmentID) {
+                       if (!in_array($attachmentID, $attachmentIDs)) {
+                               throw new UserInputException('attachmentIDs');
+                       }
+               }
+       }
+       
+       /**
+        * Updates the attachments show order.
+        */
+       public function updatePosition() {
+               $sql = "UPDATE  wcf".WCF_N."_attachment
+                       SET     showOrder = ?
+                       WHERE   attachmentID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               
+               WCF::getDB()->beginTransaction();
+               $showOrder = 1;
+               foreach ($this->parameters['attachmentIDs'] as $attachmentID) {
+                       $statement->execute(array(
+                               $showOrder++,
+                               $attachmentID
+                       ));
+               }
+               WCF::getDB()->commitTransaction();
+       }
 }