Enhanced user ignore feature
authorAlexander Ebert <ebert@woltlab.com>
Mon, 25 Apr 2016 11:10:35 +0000 (13:10 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 25 Apr 2016 11:10:41 +0000 (13:10 +0200)
* Regular content by ignored users is now converted into grayscale with
a non-hover opacity of .5
* Messages are collapsed to a single notice, but will reveal the full
message on click
* Blocking a follower will now remove the follower-state and block
future attempts to follow again while still being blocked

com.woltlab.wcf/templates/boxRecentActivitySidebar.tpl
com.woltlab.wcf/templates/recentActivityListItem.tpl
com.woltlab.wcf/templates/user.tpl
wcfsetup/install/files/js/WoltLab/WCF/BootstrapFrontend.js
wcfsetup/install/files/js/WoltLab/WCF/Ui/User/Ignore.js [new file with mode: 0644]
wcfsetup/install/files/lib/data/user/follow/UserFollowAction.class.php
wcfsetup/install/files/lib/data/user/ignore/UserIgnoreAction.class.php
wcfsetup/install/files/style/ui/userIgnore.scss [new file with mode: 0644]

index 695cdc08f0ff72be5d1ca999a21a436789771c06..6518452acaeaa064dfdcaca33f1788944d20f877 100644 (file)
@@ -1,6 +1,6 @@
 <ul class="sidebarBoxList">
        {foreach from=$eventList item=event}
-               <li class="box24">
+               <li class="box24{if $__wcf->getUserProfileHandler()->isIgnoredUser($event->getUserProfile()->userID)} ignoredUserContent{/if}">
                        <a href="{link controller='User' object=$event->getUserProfile()}{/link}" title="{$event->getUserProfile()->username}">{@$event->getUserProfile()->getAvatar()->getImageTag(24)}</a>
                        
                        <div class="sidebarBoxHeadline">
index 0e81b44c2166dc9c7edfe69f00c7cbc5b910f73d..ab4cf3af7b798136a813e6ef6de4c71229d71e7f 100644 (file)
@@ -1,6 +1,6 @@
 {foreach from=$eventList item=event}
        <li>
-               <div class="box48">
+               <div class="box48{if $__wcf->getUserProfileHandler()->isIgnoredUser($event->getUserProfile()->userID)} ignoredUserContent{/if}">
                        <a href="{link controller='User' object=$event->getUserProfile()}{/link}" title="{$event->getUserProfile()->username}">{@$event->getUserProfile()->getAvatar()->getImageTag(48)}</a>
                        
                        <div>
index 66811a5a04fab6f43e7058f6970a689595eea32a..1e1b2e2ee102c9f559e71cfddcbc9cc33df9000b 100644 (file)
                                        'wcf.user.button.unignore': '{lang}wcf.user.button.unignore{/lang}'
                                });
                                
-                               new UiUserProfileMenuItemFollow({@$user->userID}, {if $__wcf->getUserProfileHandler()->isFollowing($user->userID)}true{else}false{/if});
+                               {if !$user->isIgnoredUser($__wcf->user->userID)}
+                                       new UiUserProfileMenuItemFollow({@$user->userID}, {if $__wcf->getUserProfileHandler()->isFollowing($user->userID)}true{else}false{/if});
+                               {/if}
                                
                                {if !$user->getPermission('user.profile.cannotBeIgnored')}
-                               new UiUserProfileMenuItemIgnore({@$user->userID}, {if $__wcf->getUserProfileHandler()->isIgnoredUser($user->userID)}true{else}false{/if});
+                                       new UiUserProfileMenuItemIgnore({@$user->userID}, {if $__wcf->getUserProfileHandler()->isIgnoredUser($user->userID)}true{else}false{/if});
                                {/if}
                        });
                {/if}
index 2e82eca3c90069a5be293b0a1f936ed87530f9c4..a0ce412ce5e8de41025a8945cf59d1eddf0d958e 100644 (file)
@@ -9,11 +9,11 @@
 define(
        [
                'Ajax',                           'WoltLab/WCF/Bootstrap',         'WoltLab/WCF/Controller/Sitemap', 'WoltLab/WCF/Controller/Style/Changer',
-               'WoltLab/WCF/Controller/Popover', 'WoltLab/WCF/Ui/Page/JumpToTop'
+               'WoltLab/WCF/Controller/Popover', 'WoltLab/WCF/Ui/Page/JumpToTop', 'WoltLab/WCF/Ui/User/Ignore'
        ],
        function(
                Ajax,                              Bootstrap,                       ControllerSitemap,                ControllerStyleChanger,
-               ControllerPopover,                 UiPageJumpToTop
+               ControllerPopover,                 UiPageJumpToTop,                 UiUserIgnore
        )
 {
        "use strict";
@@ -42,6 +42,8 @@ define(
                        this._invokeBackgroundQueue(options.backgroundQueue.url, options.backgroundQueue.force);
                        
                        new UiPageJumpToTop();
+                       
+                       UiUserIgnore.init();
                },
                
                /**
diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/User/Ignore.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/User/Ignore.js
new file mode 100644 (file)
index 0000000..da515c2
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * Provides global helper methods to interact with ignored content.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLab/WCF/Ui/User/Ignore
+ */
+define(['List', 'Dom/ChangeListener'], function(List, DomChangeListener) {
+       "use strict";
+       
+       var _availableMessages = elByClass('ignoredUserMessage');
+       var _callback = null;
+       var _knownMessages = new List();
+       
+       /**
+        * @exports     WoltLab/WCF/Ui/User/Ignore
+        */
+       return {
+               /**
+                * Initializes the click handler for each ignored message and listens for
+                * newly inserted messages.
+                */
+               init: function () {
+                       _callback = this._removeClass.bind(this);
+                       
+                       this._rebuild();
+                       
+                       DomChangeListener.add('WoltLab/WCF/Ui/User/Ignore', this._rebuild.bind(this));
+               },
+               
+               /**
+                * Adds ignored messages to the collection.
+                * 
+                * @protected
+                */
+               _rebuild: function() {
+                       var message;
+                       for (var i = 0, length = _availableMessages.length; i < length; i++) {
+                               message = _availableMessages[i];
+                               
+                               if (!_knownMessages.has(message)) {
+                                       message.addEventListener(WCF_CLICK_EVENT, _callback);
+                                       
+                                       _knownMessages.add(message);
+                               }
+                       }
+               },
+               
+               /**
+                * Reveals a message on click/tap and disables the listener.
+                * 
+                * @param       {Event}         event   event object
+                * @protected
+                */
+               _removeClass: function(event) {
+                       event.preventDefault();
+                       
+                       var message = event.currentTarget;
+                       message.classList.remove('ignoredUserMessage');
+                       message.removeEventListener(WCF_CLICK_EVENT, _callback);
+                       _knownMessages.delete(message);
+               }
+       };
+});
index 574952e213d3bd88a1772a220366d87e2f3bba55..0c32416ac1c74a520cc32578adb3585da263049d 100644 (file)
@@ -41,10 +41,25 @@ class UserFollowAction extends AbstractDatabaseObjectAction implements IGroupedU
        public function validateFollow() {
                $this->readInteger('userID', false, 'data');
                
-               // validate if you're retarded
                if ($this->parameters['data']['userID'] == WCF::getUser()->userID) {
                        throw new PermissionDeniedException();
                }
+               
+               // check if current user is ignored by target user
+               $sql = "SELECT  ignoreID
+                               FROM    wcf".WCF_N."_user_ignore
+                               WHERE   userID = ?
+                                       AND ignoreUserID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       $this->parameters['data']['userID'],
+                       WCF::getUser()->userID
+               ]);
+               
+               $ignoreID = $statement->fetchSingleColumn();
+               if ($ignoreID !== false) {
+                       throw new PermissionDeniedException();
+               }
        }
        
        /**
index 103ca63d3ff38e871bc81ca5d3d1ef94dc79482d..03b5fbfc10716a65d5ce83f658bee80309abac2f 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 namespace wcf\data\user\ignore;
 use wcf\data\AbstractDatabaseObjectAction;
+use wcf\data\user\follow\UserFollow;
+use wcf\data\user\follow\UserFollowEditor;
 use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\PermissionDeniedException;
@@ -12,7 +14,7 @@ use wcf\system\WCF;
  * Executes ignored user-related actions.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    com.woltlab.wcf
  * @subpackage data.user.ignore
@@ -45,16 +47,39 @@ class UserIgnoreAction extends AbstractDatabaseObjectAction {
                $ignore = UserIgnore::getIgnore($this->parameters['data']['userID']);
                
                if (!$ignore->ignoreID) {
-                       UserIgnoreEditor::create(array(
+                       UserIgnoreEditor::create([
                                'ignoreUserID' => $this->parameters['data']['userID'],
                                'time' => TIME_NOW,
                                'userID' => WCF::getUser()->userID,
-                       ));
+                       ]);
                        
-                       UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'ignoredUserIDs');
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'ignoredUserIDs');
+                       
+                       // check if target user is following the current user
+                       $sql = "SELECT  *
+                               FROM    wcf".WCF_N."_user_follow
+                               WHERE   userID = ?
+                                       AND followUserID = ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute([
+                               $this->parameters['data']['userID'],
+                               WCF::getUser()->userID
+                       ]);
+                       
+                       $follow = $statement->fetchObject(UserFollow::class);
+                       
+                       // remove follower
+                       if ($follow !== null) {
+                               $followEditor = new UserFollowEditor($follow);
+                               $followEditor->delete();
+                               
+                               // reset storage
+                               UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'followerUserIDs');
+                               UserStorageHandler::getInstance()->reset([$this->parameters['data']['userID']], 'followingUserIDs');
+                       }
                }
                
-               return array('isIgnoredUser' => 1);
+               return ['isIgnoredUser' => 1];
        }
        
        /**
@@ -81,10 +106,10 @@ class UserIgnoreAction extends AbstractDatabaseObjectAction {
                        $ignoreEditor = new UserIgnoreEditor($ignore);
                        $ignoreEditor->delete();
                        
-                       UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'ignoredUserIDs');
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'ignoredUserIDs');
                }
                
-               return array('isIgnoredUser' => 0);
+               return ['isIgnoredUser' => 0];
        }
        
        /**
@@ -115,7 +140,7 @@ class UserIgnoreAction extends AbstractDatabaseObjectAction {
                $returnValues = parent::delete();
                
                // reset storage
-               UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'ignoredUserIDs');
+               UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'ignoredUserIDs');
                
                return $returnValues;
        }
diff --git a/wcfsetup/install/files/style/ui/userIgnore.scss b/wcfsetup/install/files/style/ui/userIgnore.scss
new file mode 100644 (file)
index 0000000..97fc7cf
--- /dev/null
@@ -0,0 +1,34 @@
+/* reduces the visual impact of content by ignored users */
+.ignoredUserContent {
+       /* no grayscale filter in IE11 due to completely lacking support */
+       
+       filter: grayscale(100%) !important; /* Firefox, Edge */
+       -webkit-filter: grayscale(100%) !important; /* Chrome, Safari, Opera */
+               
+       &:not(:hover) {
+               opacity: .5 !important;
+       }
+}
+
+.ignoredUserMessage {
+       background-color: $wcfStatusInfoBackground !important;
+       border-left: 5px solid $wcfStatusInfoBorder !important;
+       color: $wcfStatusInfoText !important;
+       cursor: pointer !important;
+       
+       &::before {
+               content: attr(data-ignored-user-message);
+               
+               @include screen-md-up {
+                       padding: 10px 20px;
+               }
+               
+               @include screen-sm-down {
+                       padding: 10px;
+               }
+       }
+       
+       > * {
+               display: none;
+       }
+}