popup notifications 1

This commit is contained in:
Yuri Kuznetsov
2014-12-05 17:46:19 +02:00
parent 554f8cc37c
commit 19784fc09c
8 changed files with 361 additions and 17 deletions
@@ -28,7 +28,7 @@ use \Espo\Core\Exceptions\Error,
class Activities extends \Espo\Core\Controllers\Base
{
public static $defaultAction = 'index';
public static $defaultAction = 'index';
public function actionListCalendarEvents($params, $data, $request)
{
@@ -48,6 +48,13 @@ class Activities extends \Espo\Core\Controllers\Base
return $service->getEvents($this->getUser()->id, $from, $to);
}
public function actionPopupNotifications()
{
$userId = $this->getUser()->id;
return $this->getService('Activities')->getPopupNotifications($userId);
}
public function actionList($params, $data, $request)
{
$name = $params['name'];
@@ -68,7 +75,7 @@ class Activities extends \Espo\Core\Controllers\Base
$scope = null;
if (!empty($where) && !empty($where['scope']) && $where['scope'] !== 'false') {
$scope = $where['scope'];
}
}
$service = $this->getService('Activities');
@@ -0,0 +1,7 @@
{
"event": {
"url": "Activities/action/popupNotifications",
"interval": 5,
"view": "Crm:Meeting.PopupNotification"
}
}
@@ -430,11 +430,23 @@ class Activities extends \Espo\Core\Services\Base
";
$sth = $pdo->prepare($sql);
$sth->execute();
$sth = $pdo->prepare($sql);
$sth->execute();
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
return $rows;
}
public function getPopupNotifications($userId)
{
return array(
array(
'id' => '43276532423',
'entityType' => 'Call',
'dateStart' => '2014-12-05 14:10',
'name' => 'Test Call'
)
);
}
}
@@ -0,0 +1,19 @@
{{#if closeButton}}
<a href="javascript:" class="pull-right close" data-action="close" aria-hidden="true">×</a>
{{/if}}
<h4>{{header}}</h4>
<div class="cell form-group">
<div class="field">
{{notificationData.name}}
</div>
</div>
<div class="cell cell-dateStart form-group">
<div class="field field-dateStart">
{{{dateStart}}}
</div>
</div>
@@ -0,0 +1,46 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Crm:Views.Meeting.PopupNotification', 'Views.PopupNotification', function (Dep) {
return Dep.extend({
type: 'event',
style: 'warning',
template: 'crm:meeting.popup-notification',
closeButton: true,
setup: function () {
},
data: function () {
return _.extend({
header: this.translate(this.notificationData.entityType, 'scopeNames')
}, Dep.prototype.data.call(this));
}
});
});
+108 -13
View File
@@ -17,7 +17,7 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
@@ -28,6 +28,8 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
updateFrequency: 10,
timeout: null,
popupNotificationsData: null,
events: {
'click a[data-action="showNotifications"]': function (e) {
@@ -40,13 +42,48 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
if (this.timeout) {
clearTimeout(this.timeout);
}
for (var name in this.popoupTimeouts) {
clearTimeout(this.popoupTimeouts[name]);
}
}, this);
this.lastId = 0;
this.shownNotificationIds = [];
this.closedNotificationIds = [];
this.popoupTimeouts = {};
delete localStorage['closePopupNotificationId'];
window.addEventListener('storage', function (e) {
if (e.key == 'closePopupNotificationId') {
var id = localStorage.getItem('closePopupNotificationId');
if (id) {
var key = 'popup-' + id;
if (this.hasView(key)) {
this.markPopupRemoved(id);
this.clearView(key);
}
}
}
}.bind(this), false);
},
afterRender: function () {
this.$badge = this.$el.find('.notifications-button');
this.$icon = this.$el.find('.notifications-button .icon');
this.$icon = this.$el.find('.notifications-button .icon');
this.checkUpdates();
this.$popupContainer = $('#popup-notifications-container');
if (!$(this.$popupContainer).size()) {
this.$popupContainer = $('<div>').attr('id', 'popup-notifications-container').addClass('hidden').appendTo('body');
}
var popupNotificationsData = this.popupNotificationsData = this.getMetadata().get('app.popupNotifications') || {};
for (var name in popupNotificationsData) {
this.checkPopupNotifications(name);
}
},
showNotRead: function (count) {
@@ -59,7 +96,7 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
this.$badge.attr('title', '');
},
checkUpdates: function () {
checkUpdates: function () {
$.ajax('Notification/action/notReadCount').done(function (count) {
if (count) {
this.showNotRead(count);
@@ -70,7 +107,65 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
this.timeout = setTimeout(function () {
this.checkUpdates();
}.bind(this), this.updateFrequency * 1000)
}.bind(this), this.updateFrequency * 1000);
},
checkPopupNotifications: function (name) {
var data = this.popupNotificationsData[name] || {};
var url = data.url;
var interval = data.interval;
if (!url || !interval) return;
$.ajax(url).done(function (list) {
list.forEach(function (d) {
this.showPopupNotification(name, d);
}, this);
}.bind(this));
this.popoupTimeouts[name] = setTimeout(function () {
this.checkPopupNotifications(name);
}.bind(this), interval * 1000);
},
showPopupNotification: function (name, data) {
var view = this.popupNotificationsData[name].view;
if (!view) return;
var id = data.id || null;
if (id) {
id = name + '_' + id;
if (~this.shownNotificationIds.indexOf(id)) return;
if (~this.closedNotificationIds.indexOf(id)) return;
} else {
id = this.lastId++;
}
this.shownNotificationIds.push(id);
this.createView('popup-' + id, view, {
notificationData: data,
id: id
}, function (view) {
view.render();
this.$popupContainer.removeClass('hidden');
this.listenTo(view, 'remove', function () {
this.markPopupRemoved(id);
localStorage.setItem('closePopupNotificationId', id);
}, this);
}.bind(this));
},
markPopupRemoved: function (id) {
var index = this.shownNotificationIds.indexOf(id);
if (index > -1) {
this.shownNotificationIds.splice(index, 1);
}
if (this.shownNotificationIds.length == 0) {
this.$popupContainer.addClass('hidden');
}
this.closedNotificationIds.push(id);
},
showNotifications: function () {
@@ -82,12 +177,12 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
'z-index': 1001,
'right': 0,
'left': 'auto'
});
});
$container.appendTo(this.$el.find('.notifications-panel-container'));
this.createView('panel', 'Notifications.Panel', {
el: '#notifications-panel',
el: '#notifications-panel',
}, function (view) {
view.render();
this.listenTo(view, 'all-read', function () {
@@ -96,24 +191,24 @@ Espo.define('Views.Notifications.Badge', 'View', function (Dep) {
}, this);
}.bind(this));
$document = $(document);
$document.on('mouseup.notification', function (e) {
if (!$container.is(e.target) && $container.has(e.target).length === 0) {
$document = $(document);
$document.on('mouseup.notification', function (e) {
if (!$container.is(e.target) && $container.has(e.target).length === 0) {
this.closeNotifications();
}
}
}.bind(this));
},
closeNotifications: function () {
$container = $('#notifications-panel');
$('#notifications-panel').remove();
$('#notifications-panel').remove();
$document = $(document);
if (this.hasView('panel')) {
this.getView('panel').remove();
};
$document.off('mouseup.notification');
$container.remove();
$document.off('mouseup.notification');
$container.remove();
},
});
@@ -0,0 +1,84 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('Views.PopupNotification', 'View', function (Dep) {
return Dep.extend({
type: 'default',
style: 'default',
closeButton: true,
init: function () {
Dep.prototype.init.call(this);
var id = this.options.id;
var containerSelector = this.containerSelector = '#' + id;
this.on('render', function () {
$(containerSelector).remove();
var className = 'popup-notification-' + Espo.Utils.toDom(this.type);
$('<div>').attr('id', id)
.addClass('popup-notification')
.addClass(className)
.addClass('popup-notification-' + this.style)
.appendTo('#popup-notifications-container');
this.setElement(containerSelector);
}, this);
this.on('after:render', function () {
this.$el.find('[data-action="close"]').on('click', function () {
this.cancel();
}.bind(this));
}, this);
this.once('remove', function () {
$(containerSelector).remove();
});
this.notificationData = this.options.notificationData;
},
data: function () {
return {
closeButton: this.closeButton,
notificationData: this.notificationData
};
},
onCancel: function () {
},
cancel: function () {
this.onCancel();
this.trigger('cancel');
this.remove();
}
});
});
+74
View File
@@ -677,3 +677,77 @@ img.avatar.avatar-link {
.complext-text a {
word-wrap: break-word;
}
#popup-notifications-container {
overflow-y: auto;
overflow-x: hidden;
right: 0px;
bottom: 0px;
position: fixed;
height: auto;
z-index: 1000;
float: right;
}
.popup-notification {
width: 400px;
padding: 14px;
background-color: @panel-bg;
border: 1px solid @main-gray;
margin-top: 10px;
}
.popup-notification a.close{
margin-top: -8px;
margin-right: -3px;
}
.popup-notification-default {
border-color: @gray-light;
}
.popup-notification-danger {
border-color: @brand-danger;
}
.popup-notification-warning {
border-color: @brand-warning;
}
.popup-notification-primary {
border-color: @brand-primary;
}
.popup-notification-success {
border-color: @brand-success;
}
.popup-notification-info {
border-color: @brand-info;
}
.popup-notification h4 {
margin-top: 0px;
}
.popup-notification-default h4 {
color: @gray-light;
}
.popup-notification-danger h4 {
color: @brand-danger;
}
.popup-notification-warning h4 {
color: @brand-warning;
}
.popup-notification-primary h4 {
color: @brand-primary;
}
.popup-notification-success h4 {
color: @brand-success;
}