Overhauled ACP user list edit icons
authorAlexander Ebert <ebert@woltlab.com>
Sat, 22 Jul 2017 18:53:51 +0000 (20:53 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 22 Jul 2017 18:54:08 +0000 (20:54 +0200)
See #2347

wcfsetup/install/files/acp/templates/userList.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/User/Editor.js [new file with mode: 0644]

index 4fb5671c95b3222c99c09bac2e506f21338df0eb..f4f950d81e7619e4e9d237c4788a70fa4df2f3cd 100644 (file)
                        WCF.ACP.User.SendNewPasswordHandler.init();
                {/if}
                
+               require(['WoltLabSuite/Core/Acp/Ui/User/Editor'], function (AcpUiUserList) {
+                       AcpUiUserList.init();
+               });
+               
                {event name='javascriptInit'}
        });
 </script>
                        
                        <tbody>
                                {foreach from=$users item=user}
-                                       <tr class="jsUserRow jsClipboardObject">
+                                       <tr class="jsUserRow jsClipboardObject" data-object-id="{@$user->userID}" data-banned="{if $user->banned}true{else}false{/if}" data-enabled="{if !$user->activationCode}true{else}false{/if}">
                                                <td class="columnMark"><input type="checkbox" class="jsClipboardItem" data-object-id="{@$user->userID}"></td>
                                                <td class="columnIcon">
+                                                       <div class="dropdown" id="userListDropdown{@$user->userID}">
+                                                               <a href="#" class="dropdownToggle button small"><span class="icon icon16 fa-pencil"></span> <span>{lang}wcf.global.button.edit{/lang}</span></a>
+                                                               
+                                                               <ul class="dropdownMenu">
+                                                                       {event name='dropdownItems'}
+                                                                       
+                                                                       {if $user->deletable}
+                                                                               <li class="dropdownDivider"></li>
+                                                                               <li><a href="#" class="jsDispatchDelete">{lang}wcf.global.button.delete{/lang}</a></li>
+                                                                       {/if}
+                                                                       
+                                                                       {if $user->editable}
+                                                                               <li class="dropdownDivider"></li>
+                                                                               <li><a href="{link controller='UserEdit' id=$user->userID}{/link}" class="jsEditLink">{lang}wcf.global.button.edit{/lang}</a></li>
+                                                                       {/if}
+                                                               </ul>
+                                                       </div>
+                                                       
+                                                       <div class="jsLegacyButtons" style="display: none">
+                                                               {* The old buttons (with the exception of the edit button) should remain here
+                                                                  for backwards-compatibility, they're sometimes referenced with JavaScript-
+                                                                  based insert calls. Clicks are forwarded to them anyway, thus there is no
+                                                                  significant downside, other than "just" some more legacy code. *}
+                                                               
+                                                               {if $user->deletable}
+                                                                       <span class="icon icon16 fa-times jsTooltip jsDeleteButton pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$user->userID}" data-confirm-message-html="{lang __encode=true}wcf.acp.user.delete.sure{/lang}"></span>
+                                                               {/if}
+                                                               {if $user->bannable}
+                                                                       <span class="icon icon16 fa-{if $user->banned}lock{else}unlock{/if} jsBanButton jsTooltip pointer" title="{lang}wcf.acp.user.{if $user->banned}unban{else}ban{/if}{/lang}" data-object-id="{@$user->userID}" data-ban-message="{lang}wcf.acp.user.ban{/lang}" data-unban-message="{lang}wcf.acp.user.unban{/lang}" data-banned="{if $user->banned}true{else}false{/if}"></span>
+                                                               {/if}
+                                                               {if $user->canBeEnabled}
+                                                                       <span class="icon icon16 fa-{if !$user->activationCode}check-square-o{else}square-o{/if} jsEnableButton jsTooltip pointer" title="{lang}wcf.acp.user.{if !$user->activationCode}disable{else}enable{/if}{/lang}" data-object-id="{@$user->userID}" data-enable-message="{lang}wcf.acp.user.enable{/lang}" data-disable-message="{lang}wcf.acp.user.disable{/lang}" data-enabled="{if !$user->activationCode}true{else}false{/if}"></span>
+                                                               {/if}
+                                                               
+                                                               {event name='rowButtons'}
+                                                       </div>
+                                               </td>
+                                               <td class="columnID columnUserID">{@$user->userID}</td>
+                                               <td class="columnIcon">{@$user->getAvatar()->getImageTag(24)}</td>
+                                               <td class="columnTitle columnUsername">
                                                        {if $user->editable}
-                                                               <a href="{link controller='UserEdit' id=$user->userID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
-                                                       {else}
-                                                               <span class="icon icon16 fa-pencil disabled" title="{lang}wcf.global.button.edit{/lang}"></span>
-                                                       {/if}
-                                                       {if $user->deletable}
-                                                               <span class="icon icon16 fa-times jsTooltip jsDeleteButton pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$user->userID}" data-confirm-message-html="{lang __encode=true}wcf.acp.user.delete.sure{/lang}"></span>
-                                                       {else}
-                                                               <span class="icon icon16 fa-times disabled" title="{lang}wcf.global.button.delete{/lang}"></span>
-                                                       {/if}
-                                                       {if $user->bannable}
-                                                               <span class="icon icon16 fa-{if $user->banned}lock{else}unlock{/if} jsBanButton jsTooltip pointer" title="{lang}wcf.acp.user.{if $user->banned}unban{else}ban{/if}{/lang}" data-object-id="{@$user->userID}" data-ban-message="{lang}wcf.acp.user.ban{/lang}" data-unban-message="{lang}wcf.acp.user.unban{/lang}" data-banned="{if $user->banned}true{else}false{/if}"></span>
+                                                               <a title="{lang}wcf.acp.user.edit{/lang}" href="{link controller='UserEdit' id=$user->userID}{/link}">{$user->username}</a>
                                                        {else}
-                                                               <span class="icon icon16 fa-{if $user->banned}lock{else}unlock{/if} disabled" title="{lang}wcf.acp.user.{if $user->banned}unban{else}ban{/if}{/lang}"></span>
+                                                               {$user->username}
                                                        {/if}
-                                                       {if $user->canBeEnabled}
-                                                               <span class="icon icon16 fa-{if !$user->activationCode}check-square-o{else}square-o{/if} jsEnableButton jsTooltip pointer" title="{lang}wcf.acp.user.{if !$user->activationCode}disable{else}enable{/if}{/lang}" data-object-id="{@$user->userID}" data-enable-message="{lang}wcf.acp.user.enable{/lang}" data-disable-message="{lang}wcf.acp.user.disable{/lang}" data-enabled="{if !$user->activationCode}true{else}false{/if}"></span>
-                                                       {else}
-                                                               <span class="icon icon16 fa-{if !$user->activationCode}check-square-o{else}square-o{/if} disabled" title="{lang}wcf.acp.user.{if !$user->activationCode}disable{else}enable{/if}{/lang}"></span>
+                                                       {if MODULE_USER_RANK}
+                                                               {if $user->getUserTitle()} <span class="badge userTitleBadge{if $user->getRank() && $user->getRank()->cssClassName} {@$user->getRank()->cssClassName}{/if}">{$user->getUserTitle()}</span>{/if}
+                                                               {if $user->getRank() && $user->getRank()->rankImage} <span class="userRankImage">{@$user->getRank()->getImage()}</span>{/if}
                                                        {/if}
-                                                       
-                                                       {event name='rowButtons'}
                                                </td>
-                                               <td class="columnID columnUserID">{@$user->userID}</td>
-                                               <td class="columnIcon">{@$user->getAvatar()->getImageTag(24)}</td>
-                                               <td class="columnTitle columnUsername">{if $user->editable}<a title="{lang}wcf.acp.user.edit{/lang}" href="{link controller='UserEdit' id=$user->userID}{/link}">{$user->username}</a>{else}{$user->username}{/if}{if MODULE_USER_RANK}{if $user->getUserTitle()} <span class="badge userTitleBadge{if $user->getRank() && $user->getRank()->cssClassName} {@$user->getRank()->cssClassName}{/if}">{$user->getUserTitle()}</span>{/if}{if $user->getRank() && $user->getRank()->rankImage} <span class="userRankImage">{@$user->getRank()->getImage()}</span>{/if}{/if}</td>
                                                
                                                {foreach from=$columnHeads key=column item=columnLanguageVariable}
                                                        <td class="column{$column|ucfirst}{if $columnStyling[$column]|isset} {$columnStyling[$column]}{/if}">{if $columnValues[$user->userID][$column]|isset}{@$columnValues[$user->userID][$column]}{/if}</td>
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/User/Editor.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/User/Editor.js
new file mode 100644 (file)
index 0000000..25aa931
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * User editing capabilities for the user list.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLabSuite/Core/Acp/Ui/User/Editor
+ * @since       3.1
+ */
+define(['Ajax', 'Core', 'Ui/SimpleDropdown'], function(Ajax, Core, UiSimpleDropdown) {
+       "use strict";
+       
+       /**
+        * @exports     WoltLabSuite/Core/Acp/Ui/User/Editor
+        */
+       return {
+               /**
+                * Initializes the edit dropdown for each user.
+                */
+               init: function () {
+                       elBySelAll('.jsUserRow', undefined, this._initUser.bind(this));
+               },
+               
+               /**
+                * Initializes the edit dropdown for a user.
+                * 
+                * @param       {Element}       userRow
+                * @protected
+                */
+               _initUser: function (userRow) {
+                       var userId = ~~elData(userRow, 'object-id');
+                       var dropdownMenu = UiSimpleDropdown.getDropdownMenu('userListDropdown' + userId);
+                       var legacyButtonContainer = elBySel('.jsLegacyButtons', userRow);
+                       
+                       UiSimpleDropdown.registerCallback('userListDropdown' + userId, (function (identifier, action) {
+                               if (action === 'open') {
+                                       this._rebuild(userId, dropdownMenu, legacyButtonContainer);
+                               }
+                       }).bind(this));
+                       
+                       var editLink = elBySel('.jsEditLink', dropdownMenu);
+                       if (editLink !== null) {
+                               elBySel('.dropdownToggle', userRow).addEventListener('dblclick', function (event) {
+                                       event.preventDefault();
+                                       
+                                       editLink.click();
+                               });
+                       }
+               },
+               
+               /**
+                * Rebuilds the dropdown by adding wrapper links for legacy buttons,
+                * that will eventually receive the click event.
+                * 
+                * @param       {int}           userId
+                * @param       {Element}       dropdownMenu
+                * @param       {Element}       legacyButtonContainer
+                * @protected
+                */
+               _rebuild: function (userId, dropdownMenu, legacyButtonContainer) {
+                       elBySelAll('.jsLegacyItem', dropdownMenu, elRemove);
+                       
+                       // inject buttons
+                       var button, item, link;
+                       var items = [];
+                       var deleteButton = null;
+                       for (var i = 0, length = legacyButtonContainer.childElementCount; i < length; i++) {
+                               button = legacyButtonContainer.children[i];
+                               if (button.classList.contains('jsDeleteButton')) {
+                                       deleteButton = button;
+                                       continue;
+                               }
+                               
+                               item = elCreate('li');
+                               item.className = 'jsLegacyItem';
+                               item.innerHTML = '<a href="#"></a>';
+                               
+                               link = item.children[0];
+                               link.textContent = elData(button, 'tooltip');
+                               (function(button) {
+                                       link.addEventListener(WCF_CLICK_EVENT, function (event) {
+                                               event.preventDefault();
+                                               
+                                               // forward click onto original button
+                                               if (button.nodeName === 'A') button.click();
+                                               else Core.triggerEvent(button, WCF_CLICK_EVENT);
+                                       });
+                               })(button);
+                               
+                               items.push(item);
+                       }
+                       
+                       while (items.length) {
+                               dropdownMenu.insertBefore(items.pop(), dropdownMenu.firstElementChild);
+                       }
+                       
+                       if (deleteButton !== null) {
+                               elBySel('.jsDispatchDelete', dropdownMenu).addEventListener(WCF_CLICK_EVENT, function (event) {
+                                       event.preventDefault();
+                                       
+                                       Core.triggerEvent(deleteButton, WCF_CLICK_EVENT);
+                               });
+                       }
+                       
+                       // check if there are visible items before each divider
+                       for (i = 0, length = dropdownMenu.childElementCount; i < length; i++) {
+                               elShow(dropdownMenu.children[i]);
+                       }
+                       
+                       var hasItem = false;
+                       for (i = 0, length = dropdownMenu.childElementCount; i < length; i++) {
+                               item = dropdownMenu.children[i];
+                               if (item.classList.contains('dropdownDivider')) {
+                                       if (!hasItem) elHide(item);
+                               }
+                               else {
+                                       hasItem = true;
+                               }
+                       }
+               }
+       };
+});