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. * Remove given notification id(s) from the table
* After they've seen it, remove it from the database
* *
* @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( $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, 'account_id' => $this->recipient->account_id,
'notify_type' => self::_type 'notify_type' => self::_type
),__LINE__,__FILE__,self::_appname); ),__LINE__,__FILE__,self::_appname);
@ -176,7 +198,7 @@ class notifications_ajax {
$message3 = 'data:text/html;charset=' . Api\Translation::charset() .';base64,'.base64_encode($message2); $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']) { 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>'; filemtime(EGW_SERVER_ROOT.'/notifications/js/notificationajaxpopup.js'). '" type="text/javascript" id="notifications_script_id" data-poll-interval="'.$popup_poll_interval.'"></script>';
echo ' echo '
<div id="egwpopup" style="display: none; z-index: 999;"> <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 id="egwpopup_list"></div>
</div> </div>
'; ';

View File

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

View File

@ -127,3 +127,14 @@ function notifications_upgrade14_3()
{ {
return $GLOBALS['setup_info']['notifications']['currentver'] = '16.1'; 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 { #egwpopup #egwpopup_list .egwpopup_message {
padding: 10px; padding: 10px;
background-color: #fafafa; background-color: #d9d9d9;
border-radius: 3px; border-radius: 3px;
margin-bottom: 10px; margin-bottom: 10px;
} }
#egwpopup #egwpopup_list .egwpopup_message:hover { #egwpopup #egwpopup_list .egwpopup_message:hover {
background-color: rgba(103, 159, 210, 0.2); background-color: rgba(103, 159, 210, 0.2);
} }
#egwpopup #egwpopup_list .egwpopup_message_seen {
background-color: #fafafa;
}
#egwpopup div#egwpopup_header { #egwpopup div#egwpopup_header {
font-size: 16px; font-size: 16px;
color: silver; color: silver;
@ -3553,7 +3556,7 @@ td.lettersearch {
width: 32px; width: 32px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
margin-top: -2px; margin-top: 1px;
margin-left: -20px; margin-left: -20px;
float: left; float: left;
} }
@ -3591,6 +3594,36 @@ td.lettersearch {
#egwpopup div#egwpopup_header .egwpopup_toggle:hover:after { #egwpopup div#egwpopup_header .egwpopup_toggle:hover:after {
background-color: gray; 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 { #egwpopup_fw_notifications {
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;

View File

@ -3524,13 +3524,16 @@ td.lettersearch {
} }
#egwpopup #egwpopup_list .egwpopup_message { #egwpopup #egwpopup_list .egwpopup_message {
padding: 10px; padding: 10px;
background-color: #fafafa; background-color: #d9d9d9;
border-radius: 3px; border-radius: 3px;
margin-bottom: 10px; margin-bottom: 10px;
} }
#egwpopup #egwpopup_list .egwpopup_message:hover { #egwpopup #egwpopup_list .egwpopup_message:hover {
background-color: rgba(103, 159, 210, 0.2); background-color: rgba(103, 159, 210, 0.2);
} }
#egwpopup #egwpopup_list .egwpopup_message_seen {
background-color: #fafafa;
}
#egwpopup div#egwpopup_header { #egwpopup div#egwpopup_header {
font-size: 16px; font-size: 16px;
color: silver; color: silver;
@ -3542,7 +3545,7 @@ td.lettersearch {
width: 32px; width: 32px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
margin-top: -2px; margin-top: 1px;
margin-left: -20px; margin-left: -20px;
float: left; float: left;
} }
@ -3580,6 +3583,36 @@ td.lettersearch {
#egwpopup div#egwpopup_header .egwpopup_toggle:hover:after { #egwpopup div#egwpopup_header .egwpopup_toggle:hover:after {
background-color: gray; 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 { #egwpopup_fw_notifications {
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;

View File

@ -49,13 +49,16 @@
} }
.egwpopup_message { .egwpopup_message {
padding: 10px; padding: 10px;
background-color: #fafafa; background-color: #d9d9d9;
border-radius: 3px; border-radius: 3px;
margin-bottom: 10px; margin-bottom: 10px;
&:hover { &:hover {
background-color: rgba(103, 159, 210, 0.2); background-color: rgba(103, 159, 210, 0.2);
} }
} }
.egwpopup_message_seen {
background-color: #fafafa;
}
} }
div#egwpopup_header { div#egwpopup_header {
font-size: 16px; font-size: 16px;
@ -67,7 +70,7 @@
width: 32px; width: 32px;
cursor: pointer; cursor: pointer;
position:relative; position:relative;
margin-top: -2px; margin-top: 1px;
margin-left: -20px; margin-left: -20px;
float:left; float:left;
&:after { &:after {
@ -104,6 +107,36 @@
background-color: gray; 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 { #egwpopup #egwpopup_list .egwpopup_message {
padding: 10px; padding: 10px;
background-color: #fafafa; background-color: #d9d9d9;
border-radius: 3px; border-radius: 3px;
margin-bottom: 10px; margin-bottom: 10px;
} }
#egwpopup #egwpopup_list .egwpopup_message:hover { #egwpopup #egwpopup_list .egwpopup_message:hover {
background-color: rgba(103, 159, 210, 0.2); background-color: rgba(103, 159, 210, 0.2);
} }
#egwpopup #egwpopup_list .egwpopup_message_seen {
background-color: #fafafa;
}
#egwpopup div#egwpopup_header { #egwpopup div#egwpopup_header {
font-size: 16px; font-size: 16px;
color: silver; color: silver;
@ -3564,7 +3567,7 @@ td.lettersearch {
width: 32px; width: 32px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
margin-top: -2px; margin-top: 1px;
margin-left: -20px; margin-left: -20px;
float: left; float: left;
} }
@ -3602,6 +3605,36 @@ td.lettersearch {
#egwpopup div#egwpopup_header .egwpopup_toggle:hover:after { #egwpopup div#egwpopup_header .egwpopup_toggle:hover:after {
background-color: gray; 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 { #egwpopup_fw_notifications {
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;