Adds the possibility to auto-trigger action effects in WCF.Clipboard
authorMatthias Schmidt <gravatronics@live.com>
Mon, 19 Mar 2012 15:54:55 +0000 (16:54 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Mon, 19 Mar 2012 15:54:55 +0000 (16:54 +0100)
If a clipboard item has the following parameters:

* actionName
* className
* objectIDs (ids of the marked objects which would be affected by the action)

the following things happen:

* An AJAX action with actionName and className is executed (if additionally a confirm message is given, the user has to handle that first before the action is executed).
* It's checked if an action object for the relevant object type and actionName exists in WCF.Clipboard exists and for each object id in objectIDs triggerEffect(objectID) on the action object is called. This way deleted objects are also removed from the table or toggled objects get updated toggle "buttons".

To achieve the second part, WCF.Action.Delete and WCF.Action.Toggle have a new method: triggerEffect() which is basically the content of _success but can now be called from WCF.Clipboard with the relevant object ids.
Furthermore UserClipboardAction returns the relevant user ids if the delete action is active.

---

Additionally, I update the javascript handling of the user list in the acp:

* The deletion button works and uses WCF.Action.Delete.
* The new WCF.Table.EmptyTablerHandler is in use.
* The above mentioned WCF.Clipboard changed are implemented which is mainly adding a few javascript lines and removing several obsolete lines from WCF.ACP.

wcfsetup/install/files/acp/js/WCF.ACP.js
wcfsetup/install/files/acp/templates/userList.tpl
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/lib/acp/page/UserListPage.class.php
wcfsetup/install/files/lib/data/user/UserEditor.class.php
wcfsetup/install/files/lib/system/clipboard/action/UserClipboardAction.class.php

index 66478f30fbd5a543675bd8b44227a4cc6080422a..7daa572a40ace57dc8a980f470d78c5d535fa233 100644 (file)
@@ -656,49 +656,6 @@ WCF.ACP.Options.prototype = {
                        }
                }
        }
-
-
-};
-
-/**
- * Namespace for WCF.ACP.User
- */
-WCF.ACP.User = {};
-
-/**
- * UserList clipboard API
- */
-WCF.ACP.User.List = function() { this.init(); };
-WCF.ACP.User.List.prototype = {
-       /**
-        * Initializes the UserList clipboard API.
-        */
-       init: function() {
-               $('body').bind('clipboardAction', $.proxy(this.handleClipboardEvent, this));
-       },
-       
-       /**
-        * Event handler for clipboard editor item actions.
-        */
-       handleClipboardEvent: function(event, type, actionName) {
-               // ignore unrelated events
-               if ((type != 'com.woltlab.wcf.user') || (actionName != 'user.delete')) return;
-               
-               var $item = $(event.target);
-               this._delete($item);
-       },
-       
-       /**
-        * Handle delete action.
-        * 
-        * @param       jQuery          item
-        */
-       _delete: function(item) {
-               var $confirmMessage = item.data('internalData')['confirmMessage'];
-               WCF.System.Confirmation.show($confirmMessage, function() {
-                       WCF.Clipboard.sendRequest(item);
-               });
-       }
 };
 
 /**
index a882400ccc4bbbc8aa9820d14a1d916664e06327..55f00e66c3a8577e3e216965d9697a9a7c27c07a 100644 (file)
@@ -3,8 +3,18 @@
 <script type="text/javascript">
        //<![CDATA[
        $(function() {
-               WCF.Clipboard.init('wcf\\acp\\page\\UserListPage', {@$hasMarkedItems});
-               new WCF.ACP.User.List();
+               var actionObjects = { };
+               actionObjects['com.woltlab.wcf.user'] = { };
+               actionObjects['com.woltlab.wcf.user']['delete'] = new WCF.Action.Delete('wcf\\data\\user\\UserAction', $('.jsUserRow'), $('#userTableContainer .wcf-menu li:first-child .wcf-badge'));
+                                       
+               WCF.Clipboard.init('wcf\\acp\\page\\UserListPage', {@$hasMarkedItems}, actionObjects);
+               
+               var options = { };
+               {if $pages > 1}
+                       options.refreshPage = true;
+               {/if}
+               
+               new WCF.Table.EmptyTableHandler($('#userTableContainer'), 'jsUserRow', options);
        });
        //]]>
 </script>
@@ -34,7 +44,7 @@
        </nav>
 </div>
 
-<div class="wcf-box wcf-boxTitle wcf-marginTop wcf-shadow1">
+<div id="userTableContainer" class="wcf-box wcf-boxTitle wcf-marginTop wcf-shadow1">
        <nav class="wcf-menu">
                <ul>
                        <li{if $action == ''} class="active"{/if}><a href="{link controller='UserList'}{/link}"><span>{lang}wcf.acp.user.list.all{/lang}</span> <span class="wcf-badge" title="{lang}wcf.acp.user.list.count{/lang}">{#$items}</span></a></li>
@@ -62,7 +72,7 @@
                        <tbody>
                                {content}
                                        {foreach from=$users item=user}
-                                               <tr id="userRow{@$user->userID}">
+                                               <tr class="jsUserRow">
                                                        <td class="columnMark"><input type="checkbox" class="jsClipboardItem" data-object-id="{@$user->userID}" /></td>
                                                        <td class="columnIcon">
                                                                {if $user->editable}
@@ -71,7 +81,7 @@
                                                                        <img src="{@$__wcf->getPath()}icon/edit1D.svg" alt="" title="{lang}wcf.acp.user.edit{/lang}" />
                                                                {/if}
                                                                {if $user->deletable}
-                                                                       <a onclick="return confirm('{lang}wcf.acp.user.delete.sure{/lang}')" href="{link controller='UserDelete' id=$user->userID}url={@$encodedURL}{/link}"><img src="{@$__wcf->getPath()}icon/delete1.svg" alt="" title="{lang}wcf.acp.user.delete{/lang}" class="jsTooltip" /></a>
+                                                                       <img src="{@$__wcf->getPath()}icon/delete1.svg" alt="" title="{lang}wcf.acp.user.delete{/lang}" class="jsTooltip jsDeleteButton" data-object-id="{@$user->userID}" data-confirm-message="{lang}wcf.acp.user.delete.sure{/lang}" />
                                                                {else}
                                                                        <img src="{@$__wcf->getPath()}icon/delete1D.svg" alt="" title="{lang}wcf.acp.user.delete{/lang}" />
                                                                {/if}
index 3ffa2e72900261d3340455f895374c9b802da938..bc15ba6973ae70637808b34a41b83146d34bed16 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * Class and function collection for WCF
  * 
- * @author     Markus Bartz, Tim Düsterhus, Alexander Ebert
+ * @author     Markus Bartz, Tim Düsterhus, Alexander Ebert, Matthias Schmidt
  * @copyright  2001-2011 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  */
@@ -495,6 +495,12 @@ WCF.Clipboard = {
         */
        _actionProxy: null,
        
+       /**
+        * action objects
+        * @var object
+        */
+       _actionObjects: {},
+       
        /**
         * list of clipboard containers
         * @var jQuery
@@ -528,9 +534,15 @@ WCF.Clipboard = {
        /**
         * Initializes the clipboard API.
         */
-       init: function(page, hasMarkedItems) {
+       init: function(page, hasMarkedItems, actionObjects) {
                this._page = page;
-               if (hasMarkedItems) this._hasMarkedItems = true;
+               this._actionObjects = actionObjects;
+               if (!actionObjects) {
+                       this._actionObjects = {};
+               }
+               if (hasMarkedItems) {
+                       this._hasMarkedItems = true;
+               }
                
                this._actionProxy = new WCF.Action.Proxy({
                        success: $.proxy(this._actionSuccess, this),
@@ -808,6 +820,7 @@ WCF.Clipboard = {
                        for (var $itemIndex in $editor.items) {
                                var $item = $editor.items[$itemIndex];
                                var $listItem = $('<li>' + $item.label + '</li>').appendTo($itemList);
+                               $listItem.data('objectType', $typeName);
                                $listItem.data('actionName', $item.actionName).data('parameters', $item.parameters);
                                $listItem.data('internalData', $item.internalData).data('url', $item.url).data('type', $typeName);
                                
@@ -825,7 +838,10 @@ WCF.Clipboard = {
                        WCF.CloseOverlayHandler.addCallback($containerID, $.proxy(this._closeLists, this));
                }
        },
-
+       
+       /**
+        * Closes the clipboard editor item list.
+        */
        _closeLists: function() {
                $('.jsClipboardEditor ul ol').each(function(index, list) {
                        $(this).removeClass('open');
@@ -844,22 +860,48 @@ WCF.Clipboard = {
                        window.location.href = $url;
                }
                
-               if ($listItem.data('parameters').className && $listItem.data('parameters').actionName) {
-                       new WCF.Action.Proxy({
-                               autoSend: true,
-                               data: {
-                                       actionName: $listItem.data('parameters').actionName,
-                                       className: $listItem.data('parameters').className,
-                                       objectIDs: this._markedObjectIDs
-                               },
-                               success: $.proxy(this._loadMarkedItems, this)
-                       });
+               if ($listItem.data('parameters').className && $listItem.data('parameters').actionName && $listItem.data('parameters').objectIDs) {
+                       var $confirmMessage = $listItem.data('internalData')['confirmMessage'];
+                       if ($confirmMessage) {
+                               WCF.System.Confirmation.show($confirmMessage, $.proxy(function() {
+                                       this._executeAJAXActions($listItem);
+                               }, this));
+                       }
+                       else {
+                               this._executeAJAXActions($listItem);
+                       }
                }
                
                // fire event
                $listItem.trigger('clipboardAction', [ $listItem.data('type'), $listItem.data('actionName'), $listItem.data('parameters') ]);
        },
        
+       /**
+        * Executes the AJAX actions for the given editor list item.
+        * 
+        * @param       jQuery          listItem
+        */
+       _executeAJAXActions: function(listItem) {
+               var objectIDs = [];
+               $.each(listItem.data('parameters').objectIDs, function(index, objectID) {
+                       objectIDs.push(parseInt(objectID));
+               });
+                       
+               new WCF.Action.Proxy({
+                       autoSend: true,
+                       data: {
+                               actionName: listItem.data('parameters').actionName,
+                               className: listItem.data('parameters').className,
+                               objectIDs: objectIDs
+                       },
+                       success: $.proxy(this._loadMarkedItems, this)
+               });
+               
+               if (this._actionObjects[listItem.data('objectType')] && this._actionObjects[listItem.data('objectType')][listItem.data('parameters').actionName]) {
+                       this._actionObjects[listItem.data('objectType')][listItem.data('parameters').actionName].triggerEffect(objectIDs);
+               }
+       },
+       
        /**
         * Sends a clipboard proxy request.
         * 
@@ -1314,10 +1356,18 @@ WCF.Action.Delete.prototype = {
         * @param       object          jqXHR
         */
        _success: function(data, textStatus, jqXHR) {
-               // remove items
+               this.triggerEffect(data.objectIDs);
+       },
+       
+       /**
+        * Triggers the delete effect for the objects with the given ids.
+        * 
+        * @param       array           objectIDs
+        */
+       triggerEffect: function(objectIDs) {
                this.containerList.each($.proxy(function(index, container) {
                        var $objectID = $(container).find('.jsDeleteButton').data('objectID');
-                       if (WCF.inArray($objectID, data.objectIDs)) {
+                       if (WCF.inArray($objectID, objectIDs)) {
                                $(container).wcfBlindOut('up', function() {
                                        $(container).empty().remove();
                                }, container);
@@ -1393,10 +1443,18 @@ WCF.Action.Toggle.prototype = {
         * @param       object          jqXHR
         */
        _success: function(data, textStatus, jqXHR) {
-               // remove items
+               this.triggerEffect(data.objectIDs);
+       },
+       
+       /**
+        * Triggers the toggle effect for the objects with the given ids.
+        * 
+        * @param       array           objectIDs
+        */
+       triggerEffect: function(objectIDs) {
                this.containerList.each($.proxy(function(index, container) {
                        var $toggleButton = $(container).find(this.toggleButtonSelector);
-                       if (WCF.inArray($toggleButton.data('objectID'), data.objectIDs)) {
+                       if (WCF.inArray($toggleButton.data('objectID'), objectIDs)) {
                                $(container).wcfHighlight();
                                
                                // toggle icon source
index 584cf339fc3f4e5bb0104c415d602053171eb38a..a7045a38db9732c74d07637d34fe8aa5ff483b6a 100755 (executable)
@@ -131,7 +131,7 @@ class UserListPage extends SortablePage {
                WCF::getTPL()->assign(array(
                        'users' => $this->users,
                        'searchID' => $this->searchID,
-                       'hasMarkedItems' => ClipboardHandler::getInstance()->hasMarkedItems(),
+                       'hasMarkedItems' => ClipboardHandler::getInstance()->hasMarkedItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user')),
                        'url' => $this->url,
                        'columnHeads' => $this->columnHeads,
                        'columnValues' => $this->columnValues
index ee43792369e1f378d024d17ebfeb8147b7c517bd..b258a97cb97a46f7c84d548f25c3453ef1a7adee 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\data\user;
 use wcf\data\user\group\UserGroup;
 use wcf\data\DatabaseObjectEditor;
+use wcf\system\clipboard\ClipboardHandler;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
 
@@ -40,6 +41,16 @@ class UserEditor extends DatabaseObjectEditor {
                return $user;
        }
        
+       /**
+        * @see wcf\data\IEditableObject::deleteAll()
+        */
+       public static function deleteAll(array $objectIDs = array()) {
+               parent::deleteAll($objectIDs);
+               
+               // unmark users
+               ClipboardHandler::getInstance()->unmark($objectIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
+       }
+       
        /**
         * @see wcf\data\DatabaseObjectEditor::update()
         */
index 35d7d59dcdf0f6ff15c963305113a554b2470d81..c09d4db771f0c31528a9498a8da54f2e6ab11fda 100644 (file)
@@ -39,14 +39,15 @@ class UserClipboardAction implements IClipboardAction {
                        break;
                        
                        case 'delete':
-                               $count = $this->validateDelete($objects);
-                               if (!$count) {
+                               $userIDs = $this->validateDelete($objects);
+                               if (!count($userIDs)) {
                                        return null;
                                }
                                
-                               $item->addInternalData('confirmMessage', WCF::getLanguage()->getDynamicVariable('wcf.clipboard.item.user.delete.confirmMessage', array('count' => $count)));
+                               $item->addInternalData('confirmMessage', WCF::getLanguage()->getDynamicVariable('wcf.clipboard.item.user.delete.confirmMessage', array('count' => count($userIDs))));
                                $item->addParameter('actionName', 'delete');
                                $item->addParameter('className', 'wcf\data\user\UserAction');
+                               $item->addParameter('objectIDs', $userIDs);
                                $item->setName('user.delete');
                        break;
                        
@@ -69,7 +70,7 @@ class UserClipboardAction implements IClipboardAction {
        }
        
        /**
-        * Returns number of users which can be deleted.
+        * Returns the ids of the users which can be deleted.
         * 
         * @param       array<wcf\data\user\User>       $objects
         * @return      integer
@@ -81,18 +82,16 @@ class UserClipboardAction implements IClipboardAction {
                }
                
                // user cannot delete itself
-               $count = count($objects);
                $userIDs = array_keys($objects);
                foreach ($userIDs as $index => $userID) {
                        if ($userID == WCF::getUser()->userID) {
-                               $count--;
                                unset($objects[$userID]);
                                unset($userIDs[$index]);
                        }
                }
                
                // no valid users found
-               if (!$count) return 0;
+               if (!count($userIDs)) return array();
                
                // fetch user to group associations
                $conditions = new PreparedStatementConditionBuilder();
@@ -114,19 +113,13 @@ class UserClipboardAction implements IClipboardAction {
                }
                
                // validate if user's group is accessible for current user
-               $count = count($objects);
-               foreach ($userIDs as $index => $userID) {
-                       if (!isset($userToGroup[$userID])) {
-                               $count--;
-                               continue;
-                       }
-                       
-                       if (!UserGroup::isAccessibleGroup($userToGroup[$userID])) {
-                               $count--;
+               foreach ($userIDs as $userID) {
+                       if (!isset($userToGroup[$userID]) || !UserGroup::isAccessibleGroup($userToGroup[$userID])) {
+                               unset($userIDs[$userID]);
                        }
                }
                
-               return $count;
+               return $userIDs;
        }
        
        /**