Added detailed list of received/given likes in user profiles
authorMarcel Werk <burntime@woltlab.com>
Tue, 27 May 2014 17:50:44 +0000 (19:50 +0200)
committerMarcel Werk <burntime@woltlab.com>
Tue, 27 May 2014 17:50:44 +0000 (19:50 +0200)
15 files changed:
com.woltlab.wcf/templates/userProfileLikeItem.tpl [new file with mode: 0644]
com.woltlab.wcf/templates/userProfileLikes.tpl [new file with mode: 0644]
com.woltlab.wcf/userProfileMenu.xml
wcfsetup/install/files/js/WCF.User.js
wcfsetup/install/files/lib/data/comment/LikeableCommentProvider.class.php
wcfsetup/install/files/lib/data/comment/response/LikeableCommentResponseProvider.class.php
wcfsetup/install/files/lib/data/like/Like.class.php
wcfsetup/install/files/lib/data/like/LikeAction.class.php
wcfsetup/install/files/lib/data/like/ViewableLike.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/like/ViewableLikeList.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/comment/manager/UserProfileCommentManager.class.php
wcfsetup/install/files/lib/system/like/IViewableLikeProvider.class.php [new file with mode: 0644]
wcfsetup/install/files/style/user.less
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

diff --git a/com.woltlab.wcf/templates/userProfileLikeItem.tpl b/com.woltlab.wcf/templates/userProfileLikeItem.tpl
new file mode 100644 (file)
index 0000000..5550bb5
--- /dev/null
@@ -0,0 +1,17 @@
+{foreach from=$likeList item=like}
+       <li>
+               <div class="box48">
+                       <a href="{link controller='User' object=$like->getUserProfile()}{/link}" title="{$like->getUserProfile()->username}" class="framed">{@$like->getUserProfile()->getAvatar()->getImageTag(48)}</a>
+                       
+                       <div>
+                               <div class="containerHeadline">
+                                       <h3><a href="{link controller='User' object=$like->getUserProfile()}{/link}" class="userLink" data-user-id="{@$like->getUserProfile()->userID}">{$like->getUserProfile()->username}</a><small> - {@$like->time|time}</small></h3> 
+                                       <p><strong>{@$like->getTitle()}</strong></p>
+                                       <small class="containerContentType">{lang}wcf.like.objectType.{@$like->getObjectTypeName()}{/lang}</small>
+                               </div>
+                               
+                               <div>{@$like->getDescription()}</div>
+                       </div>
+               </div>
+       </li>
+{/foreach}
\ No newline at end of file
diff --git a/com.woltlab.wcf/templates/userProfileLikes.tpl b/com.woltlab.wcf/templates/userProfileLikes.tpl
new file mode 100644 (file)
index 0000000..216f0ab
--- /dev/null
@@ -0,0 +1,30 @@
+<script data-relocate="true">
+       //<![CDATA[
+       $(function() {
+               WCF.Language.addObject({
+                       'wcf.like.likes.more': '{lang}wcf.like.likes.more{/lang}',
+                       'wcf.like.likes.noMoreEntries': '{lang}wcf.like.likes.noMoreEntries{/lang}'
+               });
+               
+               new WCF.User.LikeLoader({@$userID});
+       });
+       //]]>
+</script>
+
+<ul id="likeList" class="containerList recentActivityList likeList" data-last-like-time="{@$lastLikeTime}">
+       <li>
+               <ul class="buttonGroup" id="likeType">
+                       <li><a class="button small active" data-like-type="received">{lang}wcf.like.likesReceived{/lang}</a></li>
+                       <li><a class="button small" data-like-type="given">{lang}wcf.like.likesGiven{/lang}</a></li>
+               </ul>
+               
+               {if LIKE_ENABLE_DISLIKE}
+                       <ul class="buttonGroup" id="likeValue">
+                               <li><a class="button small active" data-like-value="1">{lang}wcf.like.details.like{/lang}</a></li>
+                               <li><a class="button small" data-like-value="-1">{lang}wcf.like.details.dislike{/lang}</a></li>
+                       </ul>
+               {/if}
+       </li>
+       
+       {include file='userProfileLikeItem'}
+</ul>
\ No newline at end of file
index 2ed0062d6f53fbfcb5cbfa744bd6614010389967..cd110b20304510e092081965322adf71183f9bda 100644 (file)
@@ -3,7 +3,13 @@
        <import>
                <userprofilemenuitem name="about">
                        <classname><![CDATA[wcf\system\menu\user\profile\content\AboutUserProfileMenuContent]]></classname>
+                       <showorder>3</showorder>
+               </userprofilemenuitem>
+               
+               <userprofilemenuitem name="likes">
+                       <classname><![CDATA[wcf\system\menu\user\profile\content\LikesUserProfileMenuContent]]></classname>
                        <showorder>2</showorder>
+                       <options>module_like</options>
                </userprofilemenuitem>
                
                <userprofilemenuitem name="recentActivity">
index 56d4da18a0bd750f2479905c1307371820d91a01..48cc48e1492eb62700a592fe6b7549893b18c734 100644 (file)
@@ -1605,6 +1605,164 @@ WCF.User.RecentActivityLoader = Class.extend({
        }
 });
 
+/**
+ * Loads likes once the user scrolls to the very bottom.
+ * 
+ * @param      integer         userID
+ */
+WCF.User.LikeLoader = Class.extend({
+       /**
+        * container object
+        * @var jQuery
+        */
+       _container: null,
+       
+       /**
+        * like type
+        * @var string
+        */
+       _likeType: 'received',
+       
+       /**
+        * like value
+        * @var integer
+        */
+       _likeValue: 1,
+       
+       /**
+        * button to load next events
+        * @var jQuery
+        */
+       _loadButton: null,
+       
+       /**
+        * 'no more entries' element
+        * @var jQuery
+        */
+       _noMoreEntries: null,
+       
+       /**
+        * action proxy
+        * @var WCF.Action.Proxy
+        */
+       _proxy: null,
+       
+       /**
+        * user id
+        * @var integer
+        */
+       _userID: 0,
+       
+       /**
+        * Initializes a new RecentActivityLoader object.
+        * 
+        * @param       integer         userID
+        * @param       boolean         filteredByFollowedUsers
+        */
+       init: function(userID) {
+               this._container = $('#likeList');
+               this._userID = userID;
+               
+               if (!this._userID) {
+                       console.debug("[WCF.User.RecentActivityLoader] Invalid parameter 'userID' given.");
+                       return;
+               }
+               
+               this._proxy = new WCF.Action.Proxy({
+                       success: $.proxy(this._success, this)
+               });
+               
+               var $container = $('<li class="likeListMore recentActivitiesMore"><button class="small">' + WCF.Language.get('wcf.like.likes.more') + '</button><small>' + WCF.Language.get('wcf.like.likes.noMoreEntries') + '</small></li>').appendTo(this._container);
+               this._loadButton = $container.children('button').click($.proxy(this._click, this));
+               this._noMoreEntries = $container.children('small').hide();
+               
+               if (this._container.find('> li').length == 2) {
+                       this._loadButton.hide();
+                       this._noMoreEntries.show();
+               }
+               
+               $('#likeType .button').click($.proxy(this._clickLikeType, this));
+               $('#likeValue .button').click($.proxy(this._clickLikeValue, this));
+       },
+       
+       /**
+        * Handles like type change.
+        */
+       _clickLikeType: function(event) {
+               var $button = $(event.currentTarget);
+               if (this._likeType != $button.data('likeType')) {
+                       this._likeType = $button.data('likeType');
+                       $('#likeType .button').removeClass('active');
+                       $button.addClass('active');
+                       this._reload();
+               }
+       },
+       
+       /**
+        * Handles like value change.
+        */
+       _clickLikeValue: function(event) {
+               var $button = $(event.currentTarget);
+               if (this._likeValue != $button.data('likeValue')) {
+                       this._likeValue = $button.data('likeValue');
+                       $('#likeValue .button').removeClass('active');
+                       $button.addClass('active');
+                       this._reload();
+               }
+       },
+       
+       /**
+        * Handles reload.
+        */
+       _reload: function() {
+               this._container.find('> li:not(:first-child):not(:last-child)').remove();
+               this._container.data('lastLikeTime', 0);
+               this._click();
+       },
+       
+       /**
+        * Loads next likes.
+        */
+       _click: function() {
+               this._loadButton.enable();
+               
+               var $parameters = {
+                       lastLikeTime: this._container.data('lastLikeTime'),
+                       userID: this._userID,
+                       likeType: this._likeType,
+                       likeValue: this._likeValue
+               };
+               
+               this._proxy.setOption('data', {
+                       actionName: 'load',
+                       className: 'wcf\\data\\like\\LikeAction',
+                       parameters: $parameters
+               });
+               this._proxy.sendRequest();
+       },
+       
+       /**
+        * Handles successful AJAX requests.
+        * 
+        * @param       object          data
+        * @param       string          textStatus
+        * @param       jQuery          jqXHR
+        */
+       _success: function(data, textStatus, jqXHR) {
+               if (data.returnValues.template) {
+                       $(data.returnValues.template).insertBefore(this._loadButton.parent());
+                       
+                       this._container.data('lastLikeTime', data.returnValues.lastLikeTime);
+                       this._noMoreEntries.hide();
+                       this._loadButton.show().enable();
+               }
+               else {
+                       this._noMoreEntries.show();
+                       this._loadButton.hide();
+               }
+       }
+});
+
 /**
  * Loads user profile previews.
  * 
index 408a02e41087536f98c43fe4b58090e913d74ccc..77973042f08fc25d829fd8512ac4105180d9607c 100644 (file)
@@ -4,6 +4,7 @@ use wcf\data\like\object\ILikeObject;
 use wcf\data\like\ILikeObjectTypeProvider;
 use wcf\data\object\type\AbstractObjectTypeProvider;
 use wcf\system\comment\CommentHandler;
+use wcf\system\like\IViewableLikeProvider;
 
 /**
  * Object type provider for comments
@@ -15,7 +16,7 @@ use wcf\system\comment\CommentHandler;
  * @subpackage data.comment
  * @category   Community Framework
  */
-class LikeableCommentProvider extends AbstractObjectTypeProvider implements ILikeObjectTypeProvider {
+class LikeableCommentProvider extends AbstractObjectTypeProvider implements ILikeObjectTypeProvider, IViewableLikeProvider {
        /**
         * @see \wcf\data\object\type\AbstractObjectTypeProvider::$className
         */
@@ -40,4 +41,38 @@ class LikeableCommentProvider extends AbstractObjectTypeProvider implements ILik
                $objectType = CommentHandler::getInstance()->getObjectType($comment->objectTypeID);
                return CommentHandler::getInstance()->getCommentManager($objectType->objectType)->isAccessible($comment->objectID);
        }
+       
+       /**
+        * @see \wcf\system\like\IViewableLikeProvider::prepare()
+        */
+       public function prepare(array $likes) {
+               $commentIDs = array();
+               foreach ($likes as $like) {
+                       $commentIDs[] = $like->objectID;
+               }
+       
+               // fetch comments
+               $commentList = new CommentList();
+               $commentList->getConditionBuilder()->add("comment.commentID IN (?)", array($commentIDs));
+               $commentList->readObjects();
+               $comments = $commentList->getObjects();
+               
+               // group likes by object type id
+               $likeData = array();
+               foreach ($likes as $like) {
+                       if (isset($comments[$like->objectID])) {
+                               if (!isset($likeData[$comments[$like->objectID]->objectTypeID])) {
+                                       $likeData[$comments[$like->objectID]->objectTypeID] = array();
+                               }
+                               $likeData[$comments[$like->objectID]->objectTypeID][] = $like;
+                       }
+               }
+       
+               foreach ($likeData as $objectTypeID => $likes) {
+                       $objectType = CommentHandler::getInstance()->getObjectType($objectTypeID);
+                       if (CommentHandler::getInstance()->getCommentManager($objectType->objectType) instanceof IViewableLikeProvider) {
+                               CommentHandler::getInstance()->getCommentManager($objectType->objectType)->prepare($likes);
+                       }
+               }
+       }
 }
index e6ec987a753e5572f41675cddd7e00e04a410144..463796fdb71ad594aa8810eb8c595810c38b3f8a 100644 (file)
@@ -5,6 +5,9 @@ use wcf\data\like\object\ILikeObject;
 use wcf\data\like\ILikeObjectTypeProvider;
 use wcf\data\object\type\AbstractObjectTypeProvider;
 use wcf\system\comment\CommentHandler;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\like\IViewableLikeProvider;
+use wcf\system\WCF;
 
 /**
  * Object type provider for likeable comment responses.
@@ -16,7 +19,7 @@ use wcf\system\comment\CommentHandler;
  * @subpackage data.comment.response
  * @category   Community Framework
  */
-class LikeableCommentResponseProvider extends AbstractObjectTypeProvider implements ILikeObjectTypeProvider {
+class LikeableCommentResponseProvider extends AbstractObjectTypeProvider implements ILikeObjectTypeProvider, IViewableLikeProvider {
        /**
         * @see \wcf\data\object\type\AbstractObjectTypeProvider::$className
         */
@@ -45,4 +48,47 @@ class LikeableCommentResponseProvider extends AbstractObjectTypeProvider impleme
                $objectType = CommentHandler::getInstance()->getObjectType($comment->objectTypeID);
                return CommentHandler::getInstance()->getCommentManager($objectType->objectType)->isAccessible($comment->objectID);
        }
+       
+       /**
+        * @see \wcf\system\like\IViewableLikeProvider::prepare()
+        */
+       public function prepare(array $likes) {
+               $responseIDs = array();
+               foreach ($likes as $like) {
+                       $responseIDs[] = $like->objectID;
+               }
+       
+               // get objects type ids
+               $responses = array();
+               $conditionBuilder = new PreparedStatementConditionBuilder();
+               $conditionBuilder->add('comment_response.responseID IN (?)', $responseIDs);
+               $sql = "SELECT          comment.objectTypeID, comment_response.responseID
+                       FROM            wcf".WCF_N."_comment_response comment_response
+                       LEFT JOIN       wcf".WCF_N."_comment comment
+                       ON              (comment.commentID = comment_response.commentID)
+                       ".$conditionBuilder;
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute($conditionBuilder->getParameters());
+               while ($row = $statement->fetchArray()) {
+                       $responses[$row['responseID']] = $row['objectTypeID'];
+               }
+               
+               // group likes by object type id
+               $likeData = array();
+               foreach ($likes as $like) {
+                       if (isset($responses[$like->objectID])) {
+                               if (!isset($likeData[$responses[$like->objectID]])) {
+                                       $likeData[$responses[$like->objectID]] = array();
+                               }
+                               $likeData[$responses[$like->objectID]][] = $like;
+                       }
+               }
+       
+               foreach ($likeData as $objectTypeID => $likes) {
+                       $objectType = CommentHandler::getInstance()->getObjectType($objectTypeID);
+                       if (CommentHandler::getInstance()->getCommentManager($objectType->objectType) instanceof IViewableLikeProvider) {
+                               CommentHandler::getInstance()->getCommentManager($objectType->objectType)->prepare($likes);
+                       }
+               }
+       }
 }
index 80541e42601c5fee843f7fd51905c2999cf50a5f..a051e97317bb60a8c1f2204adee6ee6634db2197 100644 (file)
@@ -72,4 +72,22 @@ class Like extends DatabaseObject {
        public static function getDatabaseTableAlias() {
                return 'like_table';
        }
+       
+       /**
+        * Returns true, if like value is a like.
+        * 
+        * @return      boolean
+        */
+       public function isLike() {
+               return ($this->likeValue == self::LIKE);
+       }
+       
+       /**
+        * Returns true, if like value is a dislike.
+        * 
+        * @return      boolean
+        */
+       public function isDislike() {
+               return ($this->likeValue == self::DISLIKE);
+       }
 }
index 0db4cc971ce09fecf78ea4f8e73b577af262f506..16119d8d045431adf6fed2919554cf9597b2abbf 100644 (file)
@@ -23,7 +23,7 @@ class LikeAction extends AbstractDatabaseObjectAction implements IGroupedUserLis
        /**
         * @see \wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
         */
-       protected $allowGuestAccess = array('getGroupedUserList', 'getLikeDetails');
+       protected $allowGuestAccess = array('getGroupedUserList', 'getLikeDetails', 'load');
        
        /**
         * @see \wcf\data\AbstractDatabaseObjectAction::$className
@@ -270,4 +270,48 @@ class LikeAction extends AbstractDatabaseObjectAction implements IGroupedUserLis
                        'template' => WCF::getTPL()->fetch('groupedUserList')
                );
        }
+       
+       /**
+        * Validates parameters to load likes.
+        */
+       public function validateLoad() {
+               $this->readInteger('lastLikeTime', true);
+               $this->readInteger('userID');
+               $this->readInteger('likeValue');
+               $this->readString('likeType');
+       }
+       
+       /**
+        * Loads a list of likes.
+        *
+        * @return      array
+        */
+       public function load() {
+               $likeList = new ViewableLikeList();
+               if ($this->parameters['lastLikeTime']) {
+                       $likeList->getConditionBuilder()->add("like_table.time < ?", array($this->parameters['lastLikeTime']));
+               }
+               if ($this->parameters['likeType'] == 'received') {
+                       $likeList->getConditionBuilder()->add("like_table.objectUserID = ?", array($this->parameters['userID']));
+               }
+               else {
+                       $likeList->getConditionBuilder()->add("like_table.userID = ?", array($this->parameters['userID']));
+               }
+               $likeList->getConditionBuilder()->add("like_table.likeValue = ?", array($this->parameters['likeValue']));
+               $likeList->readObjects();
+               $lastLikeTime = $likeList->getLastLikeTime();
+               if (!$lastLikeTime) {
+                       return array();
+               }
+       
+               // parse template
+               WCF::getTPL()->assign(array(
+                       'likeList' => $likeList
+               ));
+       
+               return array(
+                       'lastLikeTime' => $lastLikeTime,
+                       'template' => WCF::getTPL()->fetch('userProfileLikeItem')
+               );
+       }
 }
diff --git a/wcfsetup/install/files/lib/data/like/ViewableLike.class.php b/wcfsetup/install/files/lib/data/like/ViewableLike.class.php
new file mode 100644 (file)
index 0000000..1529868
--- /dev/null
@@ -0,0 +1,126 @@
+<?php
+namespace wcf\data\like;
+use wcf\data\user\UserProfile;
+use wcf\data\DatabaseObjectDecorator;
+use wcf\system\user\activity\event\UserActivityEventHandler;
+use wcf\data\object\type\ObjectTypeCache;
+
+/**
+ * Provides methods for viewable likes.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.like
+ * @category   Community Framework
+ */
+class ViewableLike extends DatabaseObjectDecorator {
+       /**
+        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        */
+       public static $baseClass = 'wcf\data\like\Like';
+       
+       /**
+        * event text
+        * @var string
+        */
+       protected $description = '';
+       
+       /**
+        * accessible by current user
+        * @var boolean
+        */
+       protected $isAccessible = false;
+       
+       /**
+        * event title
+        * @var string
+        */
+       protected $title = '';
+       
+       /**
+        * user profile
+        * @var \wcf\data\user\UserProfile
+        */
+       protected $userProfile = null;
+       
+       /**
+        * Marks this like as accessible for current user.
+        */
+       public function setIsAccessible() {
+               $this->isAccessible = true;
+       }
+       
+       /**
+        * Returns true if like is accessible by current user.
+        * 
+        * @return      boolean
+        */
+       public function isAccessible() {
+               return $this->isAccessible;
+       }
+       
+       /**
+        * Sets user profile.
+        * 
+        * @param       \wcf\data\user\UserProfile      $userProfile
+        */
+       public function setUserProfile(UserProfile $userProfile) {
+               $this->userProfile = $userProfile;
+       }
+       
+       /**
+        * Returns user profile.
+        * 
+        * @return      \wcf\data\user\UserProfile
+        */
+       public function getUserProfile() {
+               return $this->userProfile;
+       }
+       
+       /**
+        * Sets like description.
+        * 
+        * @param       string          $description
+        */
+       public function setDescription($description) {
+               $this->description = $description;
+       }
+       
+       /**
+        * Returns like description.
+        * 
+        * @return      string
+        */
+       public function getDescription() {
+               return $this->description;
+       }
+       
+       /**
+        * Sets like title.
+        * 
+        * @param       string          $title
+        */
+       public function setTitle($title) {
+               $this->title = $title;
+       }
+       
+       /**
+        * Returns like title.
+        * 
+        * @return      string
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+       
+       /**
+        * Returns the object type name.
+        * 
+        * @return      string
+        */
+       public function getObjectTypeName() {
+               return ObjectTypeCache::getInstance()->getObjectType($this->objectTypeID)->objectType;
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/like/ViewableLikeList.class.php b/wcfsetup/install/files/lib/data/like/ViewableLikeList.class.php
new file mode 100644 (file)
index 0000000..cff5673
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+namespace wcf\data\like;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\data\user\UserProfile;
+use wcf\system\like\IViewableLikeProvider;
+
+/**
+ * Represents a list of viewable likes.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.like
+ * @category   Community Framework
+ */
+class ViewableLikeList extends LikeList {
+       /**
+        * @see \wcf\data\DatabaseObjectList::$className
+        */
+       public $className = 'wcf\data\like\Like';
+       
+       /**
+        * @see \wcf\data\DatabaseObjectList::$sqlLimit
+        */
+       public $sqlLimit = 20;
+       
+       /**
+        * @see \wcf\data\DatabaseObjectList::$sqlOrderBy
+        */
+       public $sqlOrderBy = 'like_table.time DESC';
+       
+       /**
+        * @see \wcf\data\DatabaseObjectList::readObjects()
+        */
+       public function readObjects() {
+               parent::readObjects();
+               
+               $userIDs = array();
+               $likeGroups = array();
+               foreach ($this->objects as &$like) {
+                       $userIDs[] = $like->objectUserID;
+                       $like = new ViewableLike($like);
+                       
+                       if (!isset($likeGroups[$like->objectTypeID])) {
+                               $objectType = ObjectTypeCache::getInstance()->getObjectType($like->objectTypeID);
+                               $likeGroups[$like->objectTypeID] = array(
+                                       'provider' => $objectType->getProcessor(),
+                                       'objects' => array()
+                               );
+                       }
+                       
+                       $likeGroups[$like->objectTypeID]['objects'][] = $like;
+               }
+               unset($like);
+               
+               // set user profiles
+               if (!empty($userIDs)) {
+                       $userIDs = array_unique($userIDs);
+                       
+                       $users = UserProfile::getUserProfiles($userIDs);
+                       foreach ($this->objects as $like) {
+                               $like->setUserProfile($users[$like->objectUserID]);
+                       }
+               }
+               
+               // parse like
+               foreach ($likeGroups as $likeData) {
+                       if ($likeData['provider'] instanceof IViewableLikeProvider) {
+                               $likeData['provider']->prepare($likeData['objects']);
+                       }
+               }
+               
+               // validate permissions
+               foreach ($this->objects as $index => $like) {
+                       if (!$like->isAccessible()) {
+                               unset($this->objects[$index]);
+                       }
+               }
+               $this->indexToObject = array_keys($this->objects);
+       }
+       
+       /**
+        * Returns timestamp of oldest like fetched.
+        * 
+        * @return      integer
+        */
+       public function getLastLikeTime() {
+               $lastLikeTime = 0;
+               foreach ($this->objects as $like) {
+                       if (!$lastLikeTime) {
+                               $lastLikeTime = $like->time;
+                       }
+                       
+                       $lastLikeTime = min($lastLikeTime, $like->time);
+               }
+               
+               return $lastLikeTime;
+       }
+}
index aeae3d325d68fee626cced9c22272f907f468fdb..d31989174a476a2394485adacc3cba286937d9c6 100644 (file)
@@ -1,8 +1,13 @@
 <?php
 namespace wcf\system\comment\manager;
 use wcf\data\comment\response\CommentResponse;
+use wcf\data\comment\response\CommentResponseList;
 use wcf\data\comment\Comment;
+use wcf\data\comment\CommentList;
+use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileList;
+use wcf\system\like\IViewableLikeProvider;
 use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
 
@@ -16,7 +21,7 @@ use wcf\system\WCF;
  * @subpackage system.comment.manager
  * @category   Community Framework
  */
-class UserProfileCommentManager extends AbstractCommentManager {
+class UserProfileCommentManager extends AbstractCommentManager implements IViewableLikeProvider {
        /**
         * @see \wcf\system\comment\manager\AbstractCommentManager::$permissionAdd
         */
@@ -120,4 +125,102 @@ class UserProfileCommentManager extends AbstractCommentManager {
                
                return parent::canDeleteResponse($response);
        }
+       
+       /**
+        * @see \wcf\system\like\IViewableLikeProvider::prepare()
+        */
+       public function prepare(array $likes) {
+               $commentLikeObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.like.likeableObject', 'com.woltlab.wcf.comment');
+               
+               $commentIDs = $responseIDs = array();
+               foreach ($likes as $like) {
+                       if ($like->objectTypeID == $commentLikeObjectType->objectTypeID) {
+                               $commentIDs[] = $like->objectID;
+                       }
+                       else {
+                               $responseIDs[] = $like->objectID;
+                       }
+               }
+               
+               // fetch response
+               $userIDs = $responses = array();
+               if (!empty($responseIDs)) {
+                       $responseList = new CommentResponseList();
+                       $responseList->getConditionBuilder()->add("comment_response.responseID IN (?)", array($responseIDs));
+                       $responseList->readObjects();
+                       $responses = $responseList->getObjects();
+                       
+                       foreach ($responses as $response) {
+                               $commentIDs[] = $response->commentID;
+                               $userIDs[] = $response->userID;
+                       }
+               }
+               
+               // fetch comments
+               $commentList = new CommentList();
+               $commentList->getConditionBuilder()->add("comment.commentID IN (?)", array($commentIDs));
+               $commentList->readObjects();
+               $comments = $commentList->getObjects();
+               
+               // fetch users
+               $users = array();
+               foreach ($comments as $comment) {
+                       $userIDs[] = $comment->objectID;
+                       $userIDs[] = $comment->userID;
+               }
+               if (!empty($userIDs)) {
+                       $userList = new UserProfileList();
+                       $userList->getConditionBuilder()->add("user_table.userID IN (?)", array($userIDs));
+                       $userList->readObjects();
+                       $users = $userList->getObjects();
+               }
+               
+               // set message
+               foreach ($likes as $like) {
+                       if ($like->objectTypeID == $commentLikeObjectType->objectTypeID) {
+                               // comment like
+                               if (isset($comments[$like->objectID])) {
+                                       $comment = $comments[$like->objectID];
+                                       
+                                       if (isset($users[$comment->objectID]) && isset($users[$comment->userID]) && !$users[$comment->objectID]->isProtected()) {
+                                               $like->setIsAccessible();
+                                               
+                                               // short output
+                                               $text = WCF::getLanguage()->getDynamicVariable('wcf.user.profile.likes.profileComment', array(
+                                                       'commentAuthor' => $users[$comment->userID],
+                                                       'user' => $users[$comment->objectID],
+                                                       'like' => $like
+                                               ));
+                                               $like->setTitle($text);
+                                               
+                                               // output
+                                               $like->setDescription($comment->getExcerpt());
+                                       }
+                               }
+                       }
+                       else {
+                               // response like
+                               if (isset($responses[$like->objectID])) {
+                                       $response = $responses[$like->objectID];
+                                       $comment = $comments[$response->commentID];
+                                       
+                                       if (isset($users[$comment->objectID]) && isset($users[$comment->userID]) && isset($users[$response->userID]) && !$users[$comment->objectID]->isProtected()) {
+                                               $like->setIsAccessible();
+                                       
+                                               // short output
+                                               $text = WCF::getLanguage()->getDynamicVariable('wcf.user.profile.likes.profileCommentResponse', array(
+                                                       'responseAuthor' => $users[$response->userID],
+                                                       'commentAuthor' => $users[$comment->userID],
+                                                       'user' => $users[$comment->objectID],
+                                                       'like' => $like
+                                               ));
+                                               $like->setTitle($text);
+                                       
+                                               // output
+                                               $like->setDescription($response->getExcerpt());
+                                       }
+                               }
+                       }
+               }
+       }
 }
diff --git a/wcfsetup/install/files/lib/system/like/IViewableLikeProvider.class.php b/wcfsetup/install/files/lib/system/like/IViewableLikeProvider.class.php
new file mode 100644 (file)
index 0000000..dd271db
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+namespace wcf\system\like;
+
+/**
+ * Default interface for viewable like providers.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.like
+ * @category   Community Framework
+ */
+interface IViewableLikeProvider {
+       /**
+        * Prepares a list of likes for output.
+        * 
+        * @param       array<\wcf\data\like\ViewableLike>      $likes
+        */
+       public function prepare(array $likes);
+}
index 55b890a2c9674039739a185b97ef82bf8670210d..66b2e80a2c17aff77e6596c019d0fcc720738098 100644 (file)
        }
 }
 
+.likeList {
+       > li:first-child {
+               text-align: right;
+               
+               &:hover {
+                       background-color: @wcfContainerBackgroundColor;
+               }
+               
+               > ul.buttonGroup {
+                       display: inline-block;
+                       
+                       &:not(:first-child) {
+                               margin-left: @wcfGapTiny;
+                       }
+               }
+       }
+}
+
 /* dashboard boxes */
 .dashboardBoxSidebarButton {
        padding-bottom: @wcfGapLarge !important;
index 7af5c9d26680858b28ce165105ec9e6a35e4270f..1439ba78dbddda8d2410a2fc706fcefdb1c8fe5d 100644 (file)
@@ -1943,12 +1943,15 @@ Fehler sind beispielsweise:
                <item name="wcf.like.button.like"><![CDATA[Gefällt mir]]></item>
                <item name="wcf.like.button.dislike"><![CDATA[Gefällt mir nicht]]></item>
                <item name="wcf.like.likesReceived"><![CDATA[Erhaltene Likes]]></item>
+               <item name="wcf.like.likesGiven"><![CDATA[Vergebene Likes]]></item>
                <item name="wcf.like.summary"><![CDATA[{literal}{if $others == 0}{@$users.slice(0, -1).join(", ")}{if $users.length > 1} und {/if}{@$users.slice(-1)[0]}{else}{@$users.join(", ")} und {if $others == 1}einem{else}{#$others}{/if} weiteren{/if} gefällt das.{/literal}]]></item>
                <item name="wcf.like.details"><![CDATA[Details]]></item>
                <item name="wcf.like.details.like"><![CDATA[Likes]]></item>
                <item name="wcf.like.details.dislike"><![CDATA[Dislikes]]></item>
                <item name="wcf.like.objectType.com.woltlab.wcf.comment"><![CDATA[Kommentar]]></item>
                <item name="wcf.like.objectType.com.woltlab.wcf.comment.response"><![CDATA[Kommentar-Antwort]]></item>
+               <item name="wcf.like.likes.more"><![CDATA[Weitere Likes]]></item>
+               <item name="wcf.like.likes.noMoreEntries"><![CDATA[Keine weiteren Likes]]></item>
        </category>
        
        <category name="wcf.message">
@@ -2765,9 +2768,12 @@ Möchten Sie diese E-Mail-Benachrichtigung in Zukunft nicht mehr erhalten, könn
                <item name="wcf.user.profile.content.wall.commentResponse"><![CDATA[Antwort auf einen Pinnwand-Kommentar]]></item>
                <item name="wcf.user.profile.content.wall.noEntries"><![CDATA[Es wurden noch keine Einträge an der Pinnwand verfasst.]]></item>
                <item name="wcf.user.profile.menu.wall"><![CDATA[Pinnwand]]></item>
+               <item name="wcf.user.profile.menu.likes"><![CDATA[Likes]]></item>
                <item name="wcf.user.profile.recentActivity.profileComment"><![CDATA[Hat einen Kommentar an die <a href="{link controller='User' object=$user}{/link}#wall">Pinnwand von {$user->username}</a> geschrieben.]]></item>
                <item name="wcf.user.profile.recentActivity.profileCommentResponse"><![CDATA[Hat auf einen Kommentar von <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a> an der <a href="{link controller='User' object=$user}{/link}#wall">Pinnwand von {$user->username}</a> geantwortet.]]></item>
                <item name="wcf.user.profile.report"><![CDATA[Benutzerprofil melden]]></item>
+               <item name="wcf.user.profile.likes.profileComment"><![CDATA[Mag den Kommentar von <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a> an der <a href="{link controller='User' object=$user}{/link}#wall">Pinnwand von {$user->username}</a>{if $like->isDislike()} nicht{/if}.]]></item>
+               <item name="wcf.user.profile.likes.profileCommentResponse"><![CDATA[Mag die Antwort von <a href="{link controller='User' object=$responseAuthor}{/link}">{$responseAuthor->username}</a> zum Kommentar von <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a> an der <a href="{link controller='User' object=$user}{/link}#wall">Pinnwand von {$user->username}</a>{if $like->isDislike()} nicht{/if}.]]></item>
        </category>
        
        <category name="wcf.user.objectWatch">
index 754e533aa7427aefd3b976435f368dfd5f138a37..cdf253ba5e75699c012bedd05eaf4b7f4b2ddd6c 100644 (file)
@@ -1886,12 +1886,15 @@ Errors are:
                <item name="wcf.like.button.like"><![CDATA[Like]]></item>
                <item name="wcf.like.button.dislike"><![CDATA[Dislike]]></item>
                <item name="wcf.like.likesReceived"><![CDATA[Likes Received]]></item>
+               <item name="wcf.like.likesGiven"><![CDATA[Likes Given]]></item>
                <item name="wcf.like.summary"><![CDATA[{literal}{if $others == 0}{@$users.slice(0, -1).join(", ")}{if $users.length > 1} and {/if}{@$users.slice(-1)[0]}{else}{@$users.join(", ")} and {if $others == 1}one{else}{#$others}{/if} other{if $others > 1}s{/if}{/if} like{if $users.length == 1}s{/if} this.{/literal}]]></item>
                <item name="wcf.like.details"><![CDATA[Details]]></item>
                <item name="wcf.like.details.like"><![CDATA[Likes]]></item>
                <item name="wcf.like.details.dislike"><![CDATA[Dislikes]]></item>
                <item name="wcf.like.objectType.com.woltlab.wcf.comment"><![CDATA[Comment]]></item>
                <item name="wcf.like.objectType.com.woltlab.wcf.comment.response"><![CDATA[Comment Reply]]></item>
+               <item name="wcf.like.likes.more"><![CDATA[TODO: Weitere Likes]]></item>
+               <item name="wcf.like.likes.noMoreEntries"><![CDATA[TODO: Keine weiteren Likes]]></item>
        </category>
        
        <category name="wcf.message">
@@ -2617,9 +2620,12 @@ If you do not want to receive further email notifications for this event, you ca
                <item name="wcf.user.profile.content.wall.commentResponse"><![CDATA[Reply to wall comment]]></item>
                <item name="wcf.user.profile.content.wall.noEntries"><![CDATA[There are no comments yet.]]></item>
                <item name="wcf.user.profile.menu.wall"><![CDATA[Wall]]></item>
+               <item name="wcf.user.profile.menu.likes"><![CDATA[Likes]]></item>
                <item name="wcf.user.profile.recentActivity.profileComment"><![CDATA[Wrote a comment on <a href="{link controller='User' object=$user}{/link}#wall">{$user->username}’s wall</a>.]]></item>
                <item name="wcf.user.profile.recentActivity.profileCommentResponse"><![CDATA[Replied to a comment by <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a> on <a href="{link controller='User' object=$user}{/link}#wall">{$user->username}’s wall</a>.]]></item>
                <item name="wcf.user.profile.report"><![CDATA[Report User Profile]]></item>
+               <item name="wcf.user.profile.likes.profileComment"><![CDATA[TODO: Mag den Kommentar von <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a> an der <a href="{link controller='User' object=$user}{/link}#wall">Pinnwand von {$user->username}</a>{if $like->isDislike()} nicht{/if}.]]></item>
+               <item name="wcf.user.profile.likes.profileCommentResponse"><![CDATA[TODO: Mag die Antwort von <a href="{link controller='User' object=$responseAuthor}{/link}">{$responseAuthor->username}</a> zum Kommentar von <a href="{link controller='User' object=$commentAuthor}{/link}">{$commentAuthor->username}</a> an der <a href="{link controller='User' object=$user}{/link}#wall">Pinnwand von {$user->username}</a>{if $like->isDislike()} nicht{/if}.]]></item>
        </category>
        
        <category name="wcf.user.objectWatch">