WIP of Notifications System:

- Introduce notifications states
- Implement click handling for different status and update counter
This commit is contained in:
Hadi Nategh 2017-05-16 18:03:50 +02:00
parent 843331260a
commit a3b8cd339d
10 changed files with 259 additions and 59 deletions

View File

@ -131,17 +131,39 @@ class notifications_ajax {
}
/**
* Let the user confirm that they have seen the message.
* After they've seen it, remove it from the database
* Remove given notification id(s) from the table
*
* @param int|array $notify_id one or more notify_id's
* @param array|int $notify_ids one or multiple notify_id(s)
*/
public function confirm_message($notify_id)
public function delete_message($notify_ids)
{
if ($notify_id)
if ($notify_ids)
{
$this->db->delete(self::_notification_table,array(
'notify_id' => $notify_id,
'notify_id' => $notify_ids,
'account_id' => $this->recipient->account_id,
'notify_type' => self::_type
),__LINE__,__FILE__,self::_appname);
}
}
/**
* Method to update message(s) status
*
* @param int|array $notify_ids one or more notify_id(s)
* @param string $status = SEEN, status of message:
* - SEEN: message has been seen
* - UNSEEN: message has not been seen
* - DISPLAYED: message has been shown but no further status applied yet
* this status has been used more specifically for browser type
* of notifications.
*/
public function update_status($notify_ids,$status = "SEEN")
{
if ($notify_ids)
{
$this->db->update(self::_notification_table,array('notify_status' => $status),array(
'notify_id' => $notify_ids,
'account_id' => $this->recipient->account_id,
'notify_type' => self::_type
),__LINE__,__FILE__,self::_appname);
@ -176,7 +198,7 @@ class notifications_ajax {
$message3 = 'data:text/html;charset=' . Api\Translation::charset() .';base64,'.base64_encode($message2);
}
$this->response->apply('app.notifications.append',array($notification['notify_id'],$notification['notify_message'],$message3));
$this->response->apply('app.notifications.append',array($notification['notify_id'],$notification['notify_message'],$message3, $notification['notify_status']));
}
switch($this->preferences[self::_appname]['egwpopup_verbosity']) {

View File

@ -24,7 +24,9 @@ if ($GLOBALS['egw_info']['user']['apps']['notifications'])
filemtime(EGW_SERVER_ROOT.'/notifications/js/notificationajaxpopup.js'). '" type="text/javascript" id="notifications_script_id" data-poll-interval="'.$popup_poll_interval.'"></script>';
echo '
<div id="egwpopup" style="display: none; z-index: 999;">
<div id="egwpopup_header">'.lang('Notifications').'<span class="egwpopup_toggle"></span></div>
<div id="egwpopup_header">'.lang('Notifications').
'<span class="egwpopup_toggle"></span><span class="egwpopup_seenall" title='. lang('mark all as seen').'></span>'.
'<span class="egwpopup_deleteall" title='.lang('delete all messages').'></span></div>
<div id="egwpopup_list"></div>
</div>
';

View File

@ -24,8 +24,6 @@
var notification_script = document.getElementById('notifications_script_id');
var popup_poll_interval = notification_script && notification_script.getAttribute('data-poll-interval');
this.setTimeout(popup_poll_interval || 60);
jQuery('#egwpopup_ok_button').click(jQuery.proxy(this.button_ok, this));
jQuery('#notificationbell').click(jQuery.proxy(this.display, this));
// query notifictions now
this.get_notifications();
@ -65,21 +63,26 @@
* Display notifications window
*/
notifications.prototype.display = function() {
var $egwpopup,$egwpopup_list,
egwpopup_ok_button, $message,
$close;
var $egwpopup,$egwpopup_list, $message, $close, $delete_all, $mark_all;
$egwpopup = jQuery("#egwpopup");
$egwpopup_list = jQuery("#egwpopup_list");
$egwpopup = jQuery(document.getElementById("egwpopup"));
$egwpopup_list = jQuery(document.getElementById("egwpopup_list"));
egwpopup_ok_button = document.getElementById("egwpopup_ok_button");
for(var show in notifymessages)
{
var message_id = 'egwpopup_message_'+show;
if (jQuery('#'+message_id,$egwpopup_list).length > 0)
{
this.update_message_status(show, notifymessages[show]['status']);
continue;
}
$message = jQuery(document.createElement('div'))
.addClass('egwpopup_message')
.attr('id', 'egwpopup_message_'+show);
.click(jQuery.proxy(this.message_seen, this))
.attr('id', message_id);
$message[0].innerHTML = notifymessages[show]['message'];
$close = jQuery(document.createElement('span'))
.addClass('egwpopup_close')
.attr('title',egw.lang('delete message'))
.click(jQuery.proxy(this.button_close, this))
.prependTo($message);
// Activate links
@ -96,6 +99,7 @@
}
).addClass('et2_link');
$egwpopup_list.append($message);
this.update_message_status(show, notifymessages[show]['status']);
}
this.counterUpdate();
if(window.webkitNotifications && window.webkitNotifications.checkPermission() != EGW_BROWSER_NOTIFY_ALLOWED &&
@ -132,36 +136,61 @@
/**
* Callback for OK button: confirms message on server and hides display
*/
notifications.prototype.button_ok = function() {
var egwpopup;
var egwpopup_message;
egwpopup = document.getElementById("egwpopup");
egwpopup_message = document.getElementById("egwpopup_message");
egwpopup_message.scrollTop = 0;
notifications.prototype.message_seen = function(_event) {
var egwpopup_message = _event.target;
var id = egwpopup_message.id.replace(/egwpopup_message_/ig,'');
var request = egw.json("notifications.notifications_ajax.update_status", [id, "SEEN"]);
request.sendRequest(true);
this.update_message_status(id, "SEEN");
};
for(var confirmed in notifymessages) break;
var request = egw.json("notifications.notifications_ajax.confirm_message", [confirmed]);
request.sendRequest();
delete notifymessages[confirmed];
for(var id in notifymessages) break;
if (id == undefined) {
egwpopup.style.display = "none";
egwpopup_message.innerHTML = "";
this.bell("inactive");
} else {
this.display();
notifications.prototype.mark_all_seen = function()
{
if (!notifymessages || Object.keys(notifymessages).length == 0) return false;
egw.json("notifications.notifications_ajax.update_status", [Object.keys(notifymessages), "SEEN"]).sendRequest(true);
for (var id in notifymessages)
{
this.update_message_status(id, "SEEN");
}
};
notifications.prototype.update_message_status = function (_id, _status)
{
var $egwpopup_message = jQuery('#egwpopup_message_'+_id);
notifymessages[_id]['status'] = _status;
if ($egwpopup_message.length>0)
{
switch (_status)
{
case 'SEEN':
$egwpopup_message.addClass('egwpopup_message_seen');
break;
case 'UNSEEN':
case 'DISPLAYED':
$egwpopup_message.removeClass('egwpopup_message_seen');
break;
}
}
this.counterUpdate();
};
notifications.prototype.delete_all = function () {
if (!notifymessages || Object.entries(notifymessages).length == 0) return false;
egw.json("notifications.notifications_ajax.delete_message", [Object.keys(notifymessages)]).sendRequest(true);
delete(notifymessages);
jQuery("#egwpopup_list").empty();
this.counterUpdate();
};
/**
* Callback for close button: close and mark all as read
*/
notifications.prototype.button_close = function(_event) {
_event.stopPropagation();
var egwpopup_message = _event.target.parentNode;
var id = egwpopup_message.id.replace(/egwpopup_message_/ig,'');
var request = egw.json("notifications.notifications_ajax.confirm_message", [id]);
request.sendRequest();
var request = egw.json("notifications.notifications_ajax.delete_message", [id]);
request.sendRequest(true);
delete (notifymessages[id]);
egwpopup_message.style.display = 'none';
this.bell("inactive");
@ -175,18 +204,18 @@
* @param _message
* @param _browser_notify
*/
notifications.prototype.append = function(_id, _message, _browser_notify) {
notifications.prototype.append = function(_id, _message, _browser_notify, _status) {
if(!this.check_browser_notify() || typeof notifymessages[_id] != 'undefined')
{
notifymessages[_id] = {message:_message};
notifymessages[_id] = {message:_message, status:_status};
return;
}
var data = this.getData(_message);
// Prevent the same thing popping up multiple times
notifymessages[_id] = {message:_message, data: data};
notifymessages[_id] = {message:_message, data: data, status: _status};
// Notification API
if(_browser_notify)
if(_browser_notify && !_status)
{
egw.notification(data.title, {
tag: data.app+":"+_id,
@ -195,8 +224,8 @@
onclose:function(e){
// notification id
var id = this.tag.split(":");
// confirm the message
var request = egw.json("notifications.notifications_ajax.confirm_message", [id[1]]);
// delete the message
var request = egw.json("notifications.notifications_ajax.update_status", [id[1], 'DISPLAYED']);
request.sendRequest();
},
onclick:function(e){
@ -216,10 +245,6 @@
{
egw.open_link(notify.data.url,'_blank',notify.data.popup);
}
var request = egw.json("notifications.notifications_ajax.confirm_message", [id[1]]);
request.sendRequest();
delete notifymessages[id[1]];
this.close();
}
});
@ -259,10 +284,15 @@
notifications.prototype.counterUpdate = function ()
{
var $egwpopup_fw_notifications = jQuery('#egwpopup_fw_notifications');
if (Object.entries(notifymessages))
var counter = 0;
for (var id in notifymessages)
{
if (notifymessages[id]['status'] != 'SEEN') counter++;
}
if (counter > 0)
{
$egwpopup_fw_notifications.addClass('egwpopup_notify');
$egwpopup_fw_notifications.text(Object.entries(notifymessages).length);
$egwpopup_fw_notifications.text(counter);
}
else
{
@ -279,5 +309,7 @@
// toggle notifications bar
jQuery('.egwpopup_toggle').click(function(){window.app.notifications.toggle();});
jQuery('#egwpopup_fw_notifications').click(function(){window.app.notifications.toggle();});
jQuery(".egwpopup_deleteall", '#egwpopup').click(function(){window.app.notifications.delete_all()});
jQuery(".egwpopup_seenall", '#egwpopup').click(function(){window.app.notifications.mark_all_seen()});
});
})();

View File

@ -15,7 +15,7 @@ if (!defined('NOTIFICATION_APP'))
}
$setup_info[NOTIFICATION_APP]['name'] = NOTIFICATION_APP;
$setup_info[NOTIFICATION_APP]['version'] = '16.1';
$setup_info[NOTIFICATION_APP]['version'] = '17.1';
$setup_info[NOTIFICATION_APP]['app_order'] = 1;
$setup_info[NOTIFICATION_APP]['tables'] = array('egw_notificationpopup');
$setup_info[NOTIFICATION_APP]['enable'] = 2;

View File

@ -16,7 +16,8 @@ $phpgw_baseline = array(
'account_id' => array('type' => 'int','meta' => 'user','precision' => '20','nullable' => False,'comment' => 'user to notify'),
'notify_message' => array('type' => 'varchar','precision' => '16384','comment' => 'notification message'),
'notify_created' => array('type' => 'timestamp','meta' => 'timestamp','default' => 'current_timestamp','comment' => 'creation time of notification'),
'notify_type' => array('type' => 'ascii','precision' => '32','comment' => 'notification type')
'notify_type' => array('type' => 'ascii','precision' => '32','comment' => 'notification type'),
'notify_status' => array('type' => 'varchar','precision' => '32','comment' => 'notification status')
),
'pk' => array('notify_id'),
'fk' => array(),

View File

@ -127,3 +127,14 @@ function notifications_upgrade14_3()
{
return $GLOBALS['setup_info']['notifications']['currentver'] = '16.1';
}
function notifications_upgrade16_1()
{
$GLOBALS['egw_setup']->oProc->AddColumn('egw_notificationpopup','notify_status',array(
'type' => 'varchar',
'precision' => '32',
'comment' => 'notification status'
));
return $GLOBALS['setup_info']['notifications']['currentver'] = '17.1';
}

View File

@ -3535,13 +3535,16 @@ td.lettersearch {
}
#egwpopup #egwpopup_list .egwpopup_message {
padding: 10px;
background-color: #fafafa;
background-color: #d9d9d9;
border-radius: 3px;
margin-bottom: 10px;
}
#egwpopup #egwpopup_list .egwpopup_message:hover {
background-color: rgba(103, 159, 210, 0.2);
}
#egwpopup #egwpopup_list .egwpopup_message_seen {
background-color: #fafafa;
}
#egwpopup div#egwpopup_header {
font-size: 16px;
color: silver;
@ -3553,7 +3556,7 @@ td.lettersearch {
width: 32px;
cursor: pointer;
position: relative;
margin-top: -2px;
margin-top: 1px;
margin-left: -20px;
float: left;
}
@ -3591,6 +3594,36 @@ td.lettersearch {
#egwpopup div#egwpopup_header .egwpopup_toggle:hover:after {
background-color: gray;
}
#egwpopup div#egwpopup_header .egwpopup_seenall {
float: right;
width: 10px;
height: 10px;
border: 1px solid silver;
border-radius: 50%;
cursor: pointer;
margin: 4px 0px 0px 0px;
}
#egwpopup div#egwpopup_header .egwpopup_seenall:hover {
border-color: gray;
background: rgba(103, 159, 210, 0.2);
}
#egwpopup div#egwpopup_header .egwpopup_deleteall {
background-image: url(../images/delete.png);
width: 12px;
height: 12px;
background-position: center;
background-size: 12px;
float: right;
background-repeat: no-repeat;
margin-right: 15px;
margin-top: 4px;
cursor: pointer;
display: inline-block;
opacity: 0.5;
}
#egwpopup div#egwpopup_header .egwpopup_deleteall:hover {
opacity: 1;
}
#egwpopup_fw_notifications {
cursor: pointer;
display: inline-block;

View File

@ -3524,13 +3524,16 @@ td.lettersearch {
}
#egwpopup #egwpopup_list .egwpopup_message {
padding: 10px;
background-color: #fafafa;
background-color: #d9d9d9;
border-radius: 3px;
margin-bottom: 10px;
}
#egwpopup #egwpopup_list .egwpopup_message:hover {
background-color: rgba(103, 159, 210, 0.2);
}
#egwpopup #egwpopup_list .egwpopup_message_seen {
background-color: #fafafa;
}
#egwpopup div#egwpopup_header {
font-size: 16px;
color: silver;
@ -3542,7 +3545,7 @@ td.lettersearch {
width: 32px;
cursor: pointer;
position: relative;
margin-top: -2px;
margin-top: 1px;
margin-left: -20px;
float: left;
}
@ -3580,6 +3583,36 @@ td.lettersearch {
#egwpopup div#egwpopup_header .egwpopup_toggle:hover:after {
background-color: gray;
}
#egwpopup div#egwpopup_header .egwpopup_seenall {
float: right;
width: 10px;
height: 10px;
border: 1px solid silver;
border-radius: 50%;
cursor: pointer;
margin: 4px 0px 0px 0px;
}
#egwpopup div#egwpopup_header .egwpopup_seenall:hover {
border-color: gray;
background: rgba(103, 159, 210, 0.2);
}
#egwpopup div#egwpopup_header .egwpopup_deleteall {
background-image: url(../images/delete.png);
width: 12px;
height: 12px;
background-position: center;
background-size: 12px;
float: right;
background-repeat: no-repeat;
margin-right: 15px;
margin-top: 4px;
cursor: pointer;
display: inline-block;
opacity: 0.5;
}
#egwpopup div#egwpopup_header .egwpopup_deleteall:hover {
opacity: 1;
}
#egwpopup_fw_notifications {
cursor: pointer;
display: inline-block;

View File

@ -49,13 +49,16 @@
}
.egwpopup_message {
padding: 10px;
background-color: #fafafa;
background-color: #d9d9d9;
border-radius: 3px;
margin-bottom: 10px;
&:hover {
background-color: rgba(103, 159, 210, 0.2);
}
}
.egwpopup_message_seen {
background-color: #fafafa;
}
}
div#egwpopup_header {
font-size: 16px;
@ -67,7 +70,7 @@
width: 32px;
cursor: pointer;
position:relative;
margin-top: -2px;
margin-top: 1px;
margin-left: -20px;
float:left;
&:after {
@ -104,6 +107,36 @@
background-color: gray;
}
}
.egwpopup_seenall {
float: right;
width: 10px;
height: 10px;
border: 1px solid silver;
border-radius: 50%;
cursor: pointer;
margin: 4px 0px 0px 0px;
&:hover {
border-color: gray;
background: rgba(103, 159, 210, 0.2);
}
}
.egwpopup_deleteall {
background-image: url(../images/delete.png);
width: 12px;
height: 12px;
background-position: center;
background-size: 12px;
float: right;
background-repeat: no-repeat;
margin-right: 15px;
margin-top: 4px;
cursor: pointer;
display: inline-block;
opacity: 0.5;
&:hover {
opacity: 1;
}
}
}
}

View File

@ -3546,13 +3546,16 @@ td.lettersearch {
}
#egwpopup #egwpopup_list .egwpopup_message {
padding: 10px;
background-color: #fafafa;
background-color: #d9d9d9;
border-radius: 3px;
margin-bottom: 10px;
}
#egwpopup #egwpopup_list .egwpopup_message:hover {
background-color: rgba(103, 159, 210, 0.2);
}
#egwpopup #egwpopup_list .egwpopup_message_seen {
background-color: #fafafa;
}
#egwpopup div#egwpopup_header {
font-size: 16px;
color: silver;
@ -3564,7 +3567,7 @@ td.lettersearch {
width: 32px;
cursor: pointer;
position: relative;
margin-top: -2px;
margin-top: 1px;
margin-left: -20px;
float: left;
}
@ -3602,6 +3605,36 @@ td.lettersearch {
#egwpopup div#egwpopup_header .egwpopup_toggle:hover:after {
background-color: gray;
}
#egwpopup div#egwpopup_header .egwpopup_seenall {
float: right;
width: 10px;
height: 10px;
border: 1px solid silver;
border-radius: 50%;
cursor: pointer;
margin: 4px 0px 0px 0px;
}
#egwpopup div#egwpopup_header .egwpopup_seenall:hover {
border-color: gray;
background: rgba(103, 159, 210, 0.2);
}
#egwpopup div#egwpopup_header .egwpopup_deleteall {
background-image: url(../images/delete.png);
width: 12px;
height: 12px;
background-position: center;
background-size: 12px;
float: right;
background-repeat: no-repeat;
margin-right: 15px;
margin-top: 4px;
cursor: pointer;
display: inline-block;
opacity: 0.5;
}
#egwpopup div#egwpopup_header .egwpopup_deleteall:hover {
opacity: 1;
}
#egwpopup_fw_notifications {
cursor: pointer;
display: inline-block;