From 8700ed2c4b4a07bc3db2051a13c21de3c0e7c220 Mon Sep 17 00:00:00 2001 From: Marcel Werk Date: Tue, 27 May 2014 19:50:44 +0200 Subject: [PATCH] Added detailed list of received/given likes in user profiles --- .../templates/userProfileLikeItem.tpl | 17 ++ .../templates/userProfileLikes.tpl | 30 ++++ com.woltlab.wcf/userProfileMenu.xml | 6 + wcfsetup/install/files/js/WCF.User.js | 158 ++++++++++++++++++ .../comment/LikeableCommentProvider.class.php | 37 +++- .../LikeableCommentResponseProvider.class.php | 48 +++++- .../files/lib/data/like/Like.class.php | 18 ++ .../files/lib/data/like/LikeAction.class.php | 46 ++++- .../lib/data/like/ViewableLike.class.php | 126 ++++++++++++++ .../lib/data/like/ViewableLikeList.class.php | 100 +++++++++++ .../UserProfileCommentManager.class.php | 105 +++++++++++- .../like/IViewableLikeProvider.class.php | 21 +++ wcfsetup/install/files/style/user.less | 18 ++ wcfsetup/install/lang/de.xml | 6 + wcfsetup/install/lang/en.xml | 6 + 15 files changed, 738 insertions(+), 4 deletions(-) create mode 100644 com.woltlab.wcf/templates/userProfileLikeItem.tpl create mode 100644 com.woltlab.wcf/templates/userProfileLikes.tpl create mode 100644 wcfsetup/install/files/lib/data/like/ViewableLike.class.php create mode 100644 wcfsetup/install/files/lib/data/like/ViewableLikeList.class.php create mode 100644 wcfsetup/install/files/lib/system/like/IViewableLikeProvider.class.php diff --git a/com.woltlab.wcf/templates/userProfileLikeItem.tpl b/com.woltlab.wcf/templates/userProfileLikeItem.tpl new file mode 100644 index 0000000000..5550bb525a --- /dev/null +++ b/com.woltlab.wcf/templates/userProfileLikeItem.tpl @@ -0,0 +1,17 @@ +{foreach from=$likeList item=like} +
  • +
    + {@$like->getUserProfile()->getAvatar()->getImageTag(48)} + +
    +
    +

    {$like->getUserProfile()->username} - {@$like->time|time}

    +

    {@$like->getTitle()}

    + {lang}wcf.like.objectType.{@$like->getObjectTypeName()}{/lang} +
    + +
    {@$like->getDescription()}
    +
    +
    +
  • +{/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 index 0000000000..216f0ab1cd --- /dev/null +++ b/com.woltlab.wcf/templates/userProfileLikes.tpl @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/com.woltlab.wcf/userProfileMenu.xml b/com.woltlab.wcf/userProfileMenu.xml index 2ed0062d6f..cd110b2030 100644 --- a/com.woltlab.wcf/userProfileMenu.xml +++ b/com.woltlab.wcf/userProfileMenu.xml @@ -3,7 +3,13 @@ + 3 + + + + 2 + module_like diff --git a/wcfsetup/install/files/js/WCF.User.js b/wcfsetup/install/files/js/WCF.User.js index 56d4da18a0..48cc48e149 100644 --- a/wcfsetup/install/files/js/WCF.User.js +++ b/wcfsetup/install/files/js/WCF.User.js @@ -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 = $('
  • ' + WCF.Language.get('wcf.like.likes.noMoreEntries') + '
  • ').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. * diff --git a/wcfsetup/install/files/lib/data/comment/LikeableCommentProvider.class.php b/wcfsetup/install/files/lib/data/comment/LikeableCommentProvider.class.php index 408a02e410..77973042f0 100644 --- a/wcfsetup/install/files/lib/data/comment/LikeableCommentProvider.class.php +++ b/wcfsetup/install/files/lib/data/comment/LikeableCommentProvider.class.php @@ -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); + } + } + } } diff --git a/wcfsetup/install/files/lib/data/comment/response/LikeableCommentResponseProvider.class.php b/wcfsetup/install/files/lib/data/comment/response/LikeableCommentResponseProvider.class.php index e6ec987a75..463796fdb7 100644 --- a/wcfsetup/install/files/lib/data/comment/response/LikeableCommentResponseProvider.class.php +++ b/wcfsetup/install/files/lib/data/comment/response/LikeableCommentResponseProvider.class.php @@ -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); + } + } + } } diff --git a/wcfsetup/install/files/lib/data/like/Like.class.php b/wcfsetup/install/files/lib/data/like/Like.class.php index 80541e4260..a051e97317 100644 --- a/wcfsetup/install/files/lib/data/like/Like.class.php +++ b/wcfsetup/install/files/lib/data/like/Like.class.php @@ -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); + } } diff --git a/wcfsetup/install/files/lib/data/like/LikeAction.class.php b/wcfsetup/install/files/lib/data/like/LikeAction.class.php index 0db4cc971c..16119d8d04 100644 --- a/wcfsetup/install/files/lib/data/like/LikeAction.class.php +++ b/wcfsetup/install/files/lib/data/like/LikeAction.class.php @@ -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 index 0000000000..1529868c05 --- /dev/null +++ b/wcfsetup/install/files/lib/data/like/ViewableLike.class.php @@ -0,0 +1,126 @@ + + * @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 index 0000000000..cff5673dae --- /dev/null +++ b/wcfsetup/install/files/lib/data/like/ViewableLikeList.class.php @@ -0,0 +1,100 @@ + + * @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; + } +} diff --git a/wcfsetup/install/files/lib/system/comment/manager/UserProfileCommentManager.class.php b/wcfsetup/install/files/lib/system/comment/manager/UserProfileCommentManager.class.php index aeae3d325d..d31989174a 100644 --- a/wcfsetup/install/files/lib/system/comment/manager/UserProfileCommentManager.class.php +++ b/wcfsetup/install/files/lib/system/comment/manager/UserProfileCommentManager.class.php @@ -1,8 +1,13 @@ 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 index 0000000000..dd271db51a --- /dev/null +++ b/wcfsetup/install/files/lib/system/like/IViewableLikeProvider.class.php @@ -0,0 +1,21 @@ + + * @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); +} diff --git a/wcfsetup/install/files/style/user.less b/wcfsetup/install/files/style/user.less index 55b890a2c9..66b2e80a2c 100644 --- a/wcfsetup/install/files/style/user.less +++ b/wcfsetup/install/files/style/user.less @@ -133,6 +133,24 @@ } } +.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; diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 7af5c9d266..1439ba78db 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -1943,12 +1943,15 @@ Fehler sind beispielsweise: + 1} und {/if}{@$users.slice(-1)[0]}{else}{@$users.join(", ")} und {if $others == 1}einem{else}{#$others}{/if} weiteren{/if} gefällt das.{/literal}]]> + + @@ -2765,9 +2768,12 @@ Möchten Sie diese E-Mail-Benachrichtigung in Zukunft nicht mehr erhalten, könn + Pinnwand von {$user->username} geschrieben.]]> {$commentAuthor->username} an der Pinnwand von {$user->username} geantwortet.]]> + {$commentAuthor->username} an der Pinnwand von {$user->username}{if $like->isDislike()} nicht{/if}.]]> + {$responseAuthor->username} zum Kommentar von {$commentAuthor->username} an der Pinnwand von {$user->username}{if $like->isDislike()} nicht{/if}.]]> diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 754e533aa7..cdf253ba5e 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -1886,12 +1886,15 @@ Errors are: + 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}]]> + + @@ -2617,9 +2620,12 @@ If you do not want to receive further email notifications for this event, you ca + {$user->username}’s wall.]]> {$commentAuthor->username} on {$user->username}’s wall.]]> + {$commentAuthor->username} an der Pinnwand von {$user->username}{if $like->isDislike()} nicht{/if}.]]> + {$responseAuthor->username} zum Kommentar von {$commentAuthor->username} an der Pinnwand von {$user->username}{if $like->isDislike()} nicht{/if}.]]> -- 2.20.1