<script data-relocate="true">
//<![CDATA[
$(function() {
- $('.contentNavigation .jsMarkAllAsConfirmed').click(function() {
- WCF.System.Confirmation.show(WCF.Language.get('wcf.user.notification.markAllAsConfirmed.confirmMessage'), function(action) {
- if (action === 'confirm') {
- new WCF.Action.Proxy({
- autoSend: true,
- data: {
- actionName: 'markAllAsConfirmed',
- className: 'wcf\\data\\user\\notification\\UserNotificationAction'
- },
- success: function() { window.location.reload(); }
- });
- }
- });
+ WCF.Language.addObject({
+ 'wcf.user.notification.markAsConfirmed': '{lang}wcf.user.notification.markAsConfirmed{/lang}'
});
+
+ new WCF.Notification.List();
});
//]]>
</script>
</header>
<div class="container marginTop">
- <ul class="containerList"{* id="userNotificationItemList"*}>
+ <ul class="containerList userNotificationItemList">
{/if}
- <li class="jsNotificationItem{if $notification[authors] > 1} groupedNotificationItem{/if}" data-notification-id="{@$notification[notificationID]}" data-link="{$notification[event]->getLink()}" data-is-grouped="{if $notification[authors] > 1}true{else}false{/if}">
+ <li class="jsNotificationItem notificationItem{if $notification[authors] > 1} groupedNotificationItem{/if}" data-notification-id="{@$notification[notificationID]}" data-link="{$notification[event]->getLink()}" data-is-grouped="{if $notification[authors] > 1}true{else}false{/if}" data-is-confirmed="{if $notification[event]->isConfirmed()}true{else}false{/if}">
<div class="box24">
{if $notification[authors] < 2}
- {if $notification[event]->getAuthor()->userID}
- <a href="{link controller='User' object=$notification[event]->getAuthor()}{/link}" title="{$notification[event]->getAuthor()->username}" class="framed">{@$notification[event]->getAuthor()->getAvatar()->getImageTag(24)}</a>
- {else}
- <span class="framed">{@$notification[event]->getAuthor()->getAvatar()->getImageTag(24)}</span>
- {/if}
+ <div class="framed">
+ {@$notification[event]->getAuthor()->getAvatar()->getImageTag(24)}
+ </div>
<div class="details">
<p>
<p><small>{@$notification[time]|time}</small></p>
</div>
{else}
- <span class="icon icon24 fa-users"></span>
+ <div class="framed">
+ <span class="icon icon24 fa-users"></span>
+ </div>
<div class="details">
<p>
{foreach from=$notifications[notifications] item=notification}
- <li class="jsNotificationItem notificationItem{if $notification[event]->getAuthors()|count > 1} groupedNotificationItem{/if}" data-link="{$notification[event]->getLink()}" data-notification-id="{@$notification[notificationID]}">
+ <li class="jsNotificationItem notificationItem{if $notification[event]->getAuthors()|count > 1} groupedNotificationItem{/if}" data-link="{$notification[event]->getLink()}" data-notification-id="{@$notification[notificationID]}" data-is-confirmed="{if $notification[event]->isConfirmed()}true{else}false{/if}">
<span class="box24">
- {if $notification[event]->getAuthors()|count < 2}
- <div class="framed">
+ <div class="framed">
+ {if $notification[event]->getAuthors()|count < 2}
{@$notification[event]->getAuthor()->getAvatar()->getImageTag(24)}
- </div>
- {else}
- <div>
+ {else}
<span class="icon icon24 fa-users"></span>
- </div>
- {/if}
+ {/if}
+ </div>
<div>
<h3>{if !$notification[event]->isConfirmed()}<span class="badge label newContentBadge">{lang}wcf.message.new{/lang}</span>{/if} {@$notification[event]->getMessage()}</h3>
$(function() {
WCF.Language.addObject({
'wcf.user.notification.count': '{lang}wcf.user.notification.count{/lang}',
+ 'wcf.user.notification.markAsConfirmed': '{lang}wcf.user.notification.markAsConfirmed{/lang}',
'wcf.user.notification.markAllAsConfirmed': '{lang}wcf.user.notification.markAllAsConfirmed{/lang}',
'wcf.user.notification.markAllAsConfirmed.confirmMessage': '{lang}wcf.user.notification.markAllAsConfirmed.confirmMessage{/lang}',
'wcf.user.notification.noMoreNotifications': '{lang}wcf.user.notification.noMoreNotifications{/lang}',
ALTER TABLE wcf1_user_notification ADD guestTimesTriggered INT(10) NOT NULL DEFAULT 0;
ALTER TABLE wcf1_user_notification ADD userID INT(10) NOT NULL;
ALTER TABLE wcf1_user_notification ADD mailNotified TINYINT(1) NOT NULL DEFAULT 0;
-ALTER TABLE wcf1_user_notification ADD confirmed TINYINT(1) NOT NULL DEFAULT 0;
+ALTER TABLE wcf1_user_notification ADD confirmTime INT(10) NOT NULL DEFAULT 0;
ALTER TABLE wcf1_user_notification ADD baseObjectID INT(10) NOT NULL DEFAULT 0;
-ALTER TABLE wcf1_user_notification ADD KEY (userID, eventID, objectID, confirmed);
+ALTER TABLE wcf1_user_notification ADD KEY (userID, eventID, objectID, confirmTime);
+ALTER TABLE wcf1_user_notification ADD KEY (userID, confirmTime);
ALTER TABLE wcf1_user_notification_to_user DROP mailNotified;
* @copyright 2001-2014 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
*/
-WCF.Notification = {};
+WCF.Notification = { };
+
+/**
+ * Handles the notification list.
+ */
+WCF.Notification.List = Class.extend({
+ /**
+ * action proxy
+ * @var WCF.Action.Proxy
+ */
+ _proxy: null,
+
+ /**
+ * Initializes the WCF.Notification.List object.
+ */
+ init: function() {
+ this._proxy = new WCF.Action.Proxy({
+ success: $.proxy(this._success, this)
+ });
+
+ // handle 'mark all as confirmed' buttons
+ $('.contentNavigation .jsMarkAllAsConfirmed').click(function() {
+ WCF.System.Confirmation.show(WCF.Language.get('wcf.user.notification.markAllAsConfirmed.confirmMessage'), function(action) {
+ if (action === 'confirm') {
+ new WCF.Action.Proxy({
+ autoSend: true,
+ data: {
+ actionName: 'markAllAsConfirmed',
+ className: 'wcf\\data\\user\\notification\\UserNotificationAction'
+ },
+ success: function() { window.location.reload(); }
+ });
+ }
+ });
+ });
+
+ // handle regular items
+ this._convertList();
+ },
+
+ /**
+ * Converts the notification item list to be in sync with the notification dropdown.
+ */
+ _convertList: function() {
+ $('.userNotificationItemList > .notificationItem').each((function(index, item) {
+ var $item = $(item);
+
+ if (!$.browser.mobile && !$item.data('isConfirmed')) {
+ var $markAsConfirmed = $('<a href="#" class="icon icon24 fa-check green notificationItemMarkAsConfirmed jsTooltip" title="' + WCF.Language.get('wcf.user.notification.markAsConfirmed') + '" />').prependTo($item.find('> div.box24 > .framed'));
+ $markAsConfirmed.click($.proxy(this._markAsConfirmed, this));
+ }
+ }).bind(this));
+
+ WCF.DOMNodeInsertedHandler.execute();
+ },
+
+ /**
+ * Marks a single notification as confirmed.
+ *
+ * @param object event
+ */
+ _markAsConfirmed: function(event) {
+ event.preventDefault();
+
+ var $notificationID = $(event.currentTarget).parents('.notificationItem:eq(0)').data('notificationID');
+
+ this._proxy.setOption('data', {
+ actionName: 'markAsConfirmed',
+ className: 'wcf\\data\\user\\notification\\UserNotificationAction',
+ objectIDs: [ $notificationID ]
+ });
+ this._proxy.sendRequest();
+
+ return false;
+ },
+
+ /**
+ * Handles successful AJAX requests.
+ *
+ * @param object data
+ * @param string textStatus
+ * @param jQuery jqXHR
+ */
+ _success: function(data, textStatus, jqXHR) {
+ var $item = $('.userNotificationItemList > .notificationItem[data-notification-id=' + data.returnValues.notificationID + ']');
+
+ $item.data('isConfirmed', true);
+ $item.find('.notificationItemMarkAsConfirmed').remove();
+ $item.find('.newContentBadge').remove();
+ }
+});
/**
* Loads notification for the user panel.
var $badge = this._container.find('.badge');
if ($badge.length && parseInt($badge.text()) > 0) {
var $dropdownMenu = WCF.Dropdown.getDropdownMenu(this._container.wcfIdentify());
- if (!$dropdownMenu.is(':visible')) {
- $dropdownMenu.children('li.jsNotificationItem').remove();
-
- $('<li class="jsDropdownPlaceholder"><span>' + WCF.Language.get('wcf.global.loading') + '</span></li>').prependTo($dropdownMenu);
+
+ // check if there is at least one unconfirmed item
+ var $count = 0;
+ $dropdownMenu.children('li.jsNotificationItem').each(function() {
+ if (!$(this).data('isConfirmed')) {
+ $count++;
+ }
+ });
+
+ if (!$count && $count != $badge.text() && !$dropdownMenu.is(':visible')) {
+ this._resetList();
- this._didLoad = false;
this._super(event);
}
}
_after: function(dropdownMenu) {
var $items = WCF.Dropdown.getDropdownMenu(this._container.wcfIdentify()).children('li.jsNotificationItem');
- $items.each(function(index, item) {
+ $items.each((function(index, item) {
var $item = $(item);
if (!$.browser.msie) {
$('<a href="' + $item.data('link') + '" />').appendTo($item);
}
+ if (!$.browser.mobile && !$item.data('isConfirmed')) {
+ var $markAsConfirmed = $('<a href="#" class="icon icon24 fa-check green notificationItemMarkAsConfirmed jsTooltip" title="' + WCF.Language.get('wcf.user.notification.markAsConfirmed') + '" />').prependTo($item.find('> span.box24 > .framed'));
+ $markAsConfirmed.click($.proxy(this._markAsConfirmed, this));
+ }
+
$item.click(function(event) {
if (event.target.tagName !== 'A') {
window.location = $item.data('link');
}
});
+ }).bind(this));
+ },
+
+ /**
+ * Marks a notification as confirmed.
+ *
+ * @param object event
+ */
+ _markAsConfirmed: function(event) {
+ event.preventDefault();
+
+ var $notificationID = $(event.currentTarget).parents('.notificationItem:eq(0)').data('notificationID');
+
+ this._proxy.setOption('data', {
+ actionName: 'markAsConfirmed',
+ className: 'wcf\\data\\user\\notification\\UserNotificationAction',
+ objectIDs: [ $notificationID ]
});
+ this._proxy.sendRequest();
+
+ return false;
},
/**
*/
_success: function(data, textStatus, jqXHR) {
switch (data.actionName) {
+ case 'markAsConfirmed':
+ WCF.Dropdown.getDropdownMenu(this._container.wcfIdentify()).children('li.jsNotificationItem').each(function(index, item) {
+ var $item = $(item);
+ if ($item.data('notificationID') == data.returnValues.notificationID) {
+ $item.data('isConfirmed', true);
+ $item.find('.notificationItemMarkAsConfirmed').remove();
+ $item.find('.newContentBadge').remove();
+
+ return false;
+ }
+ });
+
+ this._updateBadge(data.returnValues.totalCount);
+ break;
+
case 'markAllAsConfirmed':
- $('.jsNotificationItem').remove();
+ this._resetList();
// fall through
case 'getOutstandingNotifications':
if (!data.returnValues || !data.returnValues.template) {
}
},
+ /**
+ * Resets the notification list to its initial state.
+ */
+ _resetList: function() {
+ var $dropdownMenu = WCF.Dropdown.getDropdownMenu(this._container.wcfIdentify());
+ $dropdownMenu.children('li.jsNotificationItem').remove();
+
+ $('<li class="jsDropdownPlaceholder"><span>' + WCF.Language.get('wcf.global.loading') + '</span></li>').prependTo($dropdownMenu);
+
+ this._didLoad = false;
+ },
+
/**
* Updates user notification count.
*
use wcf\system\user\notification\UserNotificationHandler;
use wcf\system\user\storage\UserStorageHandler;
use wcf\system\WCF;
+use wcf\system\exception\PermissionDeniedException;
/**
* Executes user notification-related actions.
*/
class UserNotificationAction extends AbstractDatabaseObjectAction {
/**
- * notification object
- * @var \wcf\data\user\notification\UserNotification
+ * notification editor object
+ * @var \wcf\data\user\notification\UserNotificationEditor
*/
- public $notification = null;
+ public $notificationEditor = null;
/**
* @see \wcf\data\AbstractDatabaseObjectAction::create()
$notificationList->getConditionBuilder()->add("eventID = ?", array($this->parameters['data']['eventID']));
$notificationList->getConditionBuilder()->add("eventHash = ?", array($this->parameters['data']['eventHash']));
$notificationList->getConditionBuilder()->add("userID IN (?)", array(array_keys($this->parameters['recipients'])));
- $notificationList->getConditionBuilder()->add("confirmed = ?", array(0));
+ $notificationList->getConditionBuilder()->add("confirmTime = ?", array(0));
$notificationList->readObjects();
$existingNotifications = array();
foreach ($notificationList as $notification) {
'notifications' => $notifications
));
- $markAsConfirmed = array();
- foreach ($notifications['notifications'] as $notification) {
- if (!$notification['event']->isConfirmed()) {
- $markAsConfirmed[] = $notification['notificationID'];
- }
- }
-
- if (!empty($markAsConfirmed)) {
- $conditions = new PreparedStatementConditionBuilder();
- $conditions->add("notificationID IN (?)", array($markAsConfirmed));
-
- // mark notifications as confirmed
- $sql = "UPDATE wcf".WCF_N."_user_notification
- SET confirmed = 1
- ".$conditions;
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute($conditions->getParameters());
-
- // delete notification_to_user assignments (mimic legacy notification system)
- $sql = "DELETE FROM wcf".WCF_N."_user_notification_to_user
- ".$conditions;
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute($conditions->getParameters());
-
- // reset user storage
- UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount');
- }
-
return array(
'template' => WCF::getTPL()->fetch('notificationListOustanding'),
'totalCount' => $notifications['notificationCount']
);
}
+ /**
+ * Validates parameters to mark a notification as confirmed.
+ */
+ public function validateMarkAsConfirmed() {
+ $this->notificationEditor = $this->getSingleObject();
+ if ($this->notificationEditor->userID != WCF::getUser()->userID) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * Marks a notification as confirmed.
+ *
+ * @return array
+ */
+ public function markAsConfirmed() {
+ UserNotificationHandler::getInstance()->markAsConfirmedByID($this->notificationEditor->notificationID);
+
+ return array(
+ 'notificationID' => $this->notificationEditor->notificationID,
+ 'totalCount' => UserNotificationHandler::getInstance()->getNotificationCount(true)
+ );
+ }
+
/**
* Validates parameters to mark all notifications of current user as confirmed.
*/
public function markAllAsConfirmed() {
// remove notifications for this user
$sql = "UPDATE wcf".WCF_N."_user_notification
- SET confirmed = ?
+ SET confirmTime = ?
WHERE userID = ?";
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute(array(
- 1,
+ TIME_NOW,
WCF::getUser()->userID
));
+ // delete notification_to_user assignments (mimic legacy notification system)
+ $sql = "DELETE FROM wcf".WCF_N."_user_notification_to_user
+ WHERE userID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array(WCF::getUser()->userID));
+
// reset notification count
UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount');
}
*/
public function markAsConfirmed() {
$this->update(array(
- 'confirmed' => 1,
+ 'confirmTime' => TIME_NOW,
'mailNotified' => 1
));
<?php
namespace wcf\page;
-use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\menu\user\UserMenu;
use wcf\system\user\notification\UserNotificationHandler;
-use wcf\system\user\storage\UserStorageHandler;
use wcf\system\WCF;
/**
parent::readData();
$this->notifications = UserNotificationHandler::getInstance()->getNotifications($this->sqlLimit, $this->sqlOffset, true);
-
- $markAsConfirmed = array();
- foreach ($this->notifications['notifications'] as $notification) {
- if (!$notification['event']->isConfirmed()) {
- $markAsConfirmed[] = $notification['notificationID'];
- }
- }
-
- if (!empty($markAsConfirmed)) {
- $conditions = new PreparedStatementConditionBuilder();
- $conditions->add("notificationID IN (?)", array($markAsConfirmed));
-
- // mark notifications as confirmed
- $sql = "UPDATE wcf".WCF_N."_user_notification
- SET confirmed = 1
- ".$conditions;
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute($conditions->getParameters());
-
- // delete notification_to_user assignments (mimic legacy notification system)
- $sql = "DELETE FROM wcf".WCF_N."_user_notification_to_user
- ".$conditions;
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute($conditions->getParameters());
-
- // reset user storage
- UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount');
- }
}
/**
$conditions->add("userID IN (?)", array($recipientIDs));
$conditions->add("eventID = ?", array($event->eventID));
$conditions->add("eventHash = ?", array($event->getEventHash()));
- $conditions->add("confirmed = ?", array(0));
+ $conditions->add("confirmTime = ?", array(0));
$sql = "SELECT notificationID, userID
FROM wcf".WCF_N."_user_notification
$sql = "SELECT COUNT(*) AS count
FROM wcf".WCF_N."_user_notification
WHERE userID = ?
- AND confirmed = ?";
+ AND confirmTime = ?";
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute(array(
WCF::getUser()->userID,
}
$returnValues = $this->processNotifications($notifications, true);
- $returnValues['notificationCount'] = max($notificationCount - $count, 0);
+ $returnValues['notificationCount'] = $notificationCount;
return $returnValues;
}
$orderBy = 'notification.time DESC';
if ($filterByConfirmed !== null) {
// fetch the oldest, unconfirmed notifications, order will be reversed using PHP
- $conditions->add("notification.confirmed = ?", array($filterByConfirmed));
+ if ($filterByConfirmed == 0) {
+ $conditions->add("notification.confirmTime = ?", array(0));
+ }
+ else {
+ // consider only notifications marked as confirmed in the past 48 hours (86400 = 1 day)
+ $conditions->add("notification.confirmTime >= ?", array(TIME_NOW - (2 * 86400)));
+ }
if ($filterByConfirmed = 0) {
$orderBy = 'notification.time ASC';
'time' => $notification->time
);
- $data['confirmed'] = $notification->confirmed;
+ $data['confirmed'] = ($notification->confirmTime > 0);
$notifications[] = $data;
}
if (!empty($objectIDs)) $conditions->add("objectID IN (?)", array($objectIDs));
$sql = "UPDATE wcf".WCF_N."_user_notification
- SET confirmed = ?
+ SET confirmTime = ?
".$conditions;
$statement = WCF::getDB()->prepareStatement($sql);
$parameters = $conditions->getParameters();
- array_unshift($parameters, 1);
+ array_unshift($parameters, TIME_NOW);
$statement->execute($parameters);
// delete notification_to_user assignments (mimic legacy notification system)
WHERE notificationID NOT IN (
SELECT notificationID
FROM wcf".WCF_N."_user_notification
- WHERE confirmed = ?
+ WHERE confirmTime = ?
)";
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute(array(0));
}
}
+ /**
+ * Marks a single notification id as confirmed.
+ *
+ * @param integer $notificationID
+ */
+ public function markAsConfirmedByID($notificationID) {
+ $this->markAsConfirmedByIDs(array($notificationID));
+ }
+
+ /**
+ * Marks a list of notification ids as confirmed.
+ *
+ * @param array<integer> $notificationIDs
+ */
+ public function markAsConfirmedByIDs(array $notificationIDs) {
+ if (empty($notificationIDs)) {
+ return;
+ }
+
+ $conditions = new PreparedStatementConditionBuilder();
+ $conditions->add("notificationID IN (?)", array($notificationIDs));
+
+ // mark notifications as confirmed
+ $sql = "UPDATE wcf".WCF_N."_user_notification
+ SET confirmTime = ?
+ ".$conditions;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $parameters = $conditions->getParameters();
+ array_unshift($parameters, TIME_NOW);
+ $statement->execute($parameters);
+
+ // delete notification_to_user assignments (mimic legacy notification system)
+ $sql = "DELETE FROM wcf".WCF_N."_user_notification_to_user
+ ".$conditions;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute($conditions->getParameters());
+
+ // reset user storage
+ UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount');
+ }
+
/**
* Returns the user's notification setting for the given event.
*
* @see \wcf\system\user\notification\event\IUserNotificationEvent::isConfirmed()
*/
public function isConfirmed() {
- return ($this->notification->confirmed == 1);
+ return ($this->notification->confirmTime > 0);
}
/**
&.notificationItem {
&.groupedNotificationItem > span {
- > div:first-child {
- padding: 4px 2px 2px;
+ > .framed > span.fa-users:before {
+ position: relative;
+ top: 3px;
}
> div + div {
}
}
+ &:hover > span > .framed {
+ > .notificationItemMarkAsConfirmed {
+ height: 24px;
+ display: block;
+ width: 24px;
+
+ &:before {
+ position: relative;
+ top: 3px;
+ }
+ }
+
+ > .notificationItemMarkAsConfirmed ~ img,
+ > .notificationItemMarkAsConfirmed ~ .fa-users {
+ display: none;
+ }
+ }
+
> span {
cursor: pointer;
white-space: normal;
+
+ > .framed > .notificationItemMarkAsConfirmed {
+ display: none;
+ }
}
}
}
}
/* user notifications */
-#userNotificationItemList > .groupedNotificationItem p > a {
- font-weight: bold;
+.userNotificationItemList > .notificationItem {
+ &.groupedNotificationItem > div > .framed > span.fa-users:before {
+ position: relative;
+ top: 3px;
+ }
+
+ &:hover > div > .framed {
+ > .notificationItemMarkAsConfirmed {
+ height: 24px;
+ display: block;
+ width: 24px;
+
+ &:before {
+ position: relative;
+ top: 3px;
+ }
+ }
+
+ > .notificationItemMarkAsConfirmed ~ img,
+ > .notificationItemMarkAsConfirmed ~ .fa-users {
+ display: none;
+ }
+ }
+
+ > div > .framed > .notificationItemMarkAsConfirmed {
+ display: none;
+ }
}
.paidSubscriptionTeaserList {
userID INT(10) NOT NULL,
time INT(10) NOT NULL DEFAULT 0,
mailNotified TINYINT(1) NOT NULL DEFAULT 0,
- confirmed TINYINT(1) NOT NULL DEFAULT 0,
+ confirmTime INT(10) NOT NULL DEFAULT 0,
additionalData TEXT,
- KEY (userID, eventID, objectID, confirmed)
+ KEY (userID, eventID, objectID, confirmTime),
+ KEY (userID, confirmTime)
);
-- notification authors (stacking)