Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernise + marking notifications as "unread" #27

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ Notifications are short messages that notify users of something that occurred in
Requirements
------------

- PHP 7.1+
- PHP 8.1+
- gmp
- mbstring
- curl
- openssl

- PHP 7.2+ is recommended for better performance.

Installation
------------

Expand Down Expand Up @@ -316,4 +314,4 @@ If you customize the HTML template remember to include a button with id 'js-web-
</div>
```

Remember to place the service-worker.js file in the web root in order to serve the service worker when the WebNotifications widget is initialized.
Remember to place the service-worker.js file in the web root in order to serve the service worker when the WebNotifications widget is initialized.
164 changes: 97 additions & 67 deletions assets/js/notifications.js
Original file line number Diff line number Diff line change
@@ -1,171 +1,201 @@
'use strict';

/**
* notifications plugin
*/

var Notifications = (function(opts) {
if(!opts.id){
const Notifications = (function (opts) {
if (!opts.id) {
throw new Error('Notifications: the param id is required.');
}

var elem = $('#'+opts.id);
if(!elem.length){
const elem = $('#' + opts.id);
if (!elem.length) {
throw Error('Notifications: the element was not found.');
}

var options = $.extend({
const options = $.extend({
pollInterval: 60000,
xhrTimeout: 2000,
readLabel: 'read',
readLabel: 'mark as unread',
markAsReadLabel: 'mark as read'
}, opts);

/**
* Renders a notification row
* Renders a notification row.
*
* @param object The notification instance
* @returns {jQuery|HTMLElement|*}
*/
var renderRow = function (object) {
var html = '<div href="#" class="dropdown-item notification-item' + (object.read != '0' ? ' read' : '') + '"' +
const renderRow = function (object) {
const html = '<div href="#" class="dropdown-item notification-item' + (object.read != '0' ? ' read' : '') + '"' +
' data-id="' + object.id + '"' +
' data-class="' + object.class + '"' +
' data-key="' + object.key + '">' +
'<span class="icon"></span> '+
'<span class="icon"></span> ' +
'<span class="message">' + object.message + '</span>' +
'<small class="timeago">' + object.timeago + '</small>' +
'<span class="mark-read" data-toggle="tooltip" title="' + (object.read != '0' ? options.readLabel : options.markAsReadLabel) + '"></span>' +
'</div>';
return $(html);
};

var showList = function() {
var list = elem.find('.notifications-list');
/**
* Initialise the "mark as read"/"mark as unread" buttons.
*/
const initMarkReadButtons = function () {
$('.notifications-list').find('.mark-read').off('click').on('click', function (e) {
e.stopPropagation();
const item = $(this).closest('.notification-item');
let url = opts.readUrl;
let callback = displayAsRead;
if (item.hasClass('read')) {
url = opts.unreadUrl;
callback = displayAsUnread;
}
const mark = $(this);
$.ajax({
url: url,
type: 'GET',
data: {id: item.data('id')},
dataType: 'json',
timeout: opts.xhrTimeout,
success: function (data) {
callback(mark);
}
});
}).tooltip('dispose').tooltip();
};

/**
* Render out the full list of notifications.
*/
const showList = function () {
let list = elem.find('.notifications-list');
$.ajax({
url: options.url,
type: "GET",
dataType: "json",
type: 'GET',
dataType: 'json',
timeout: opts.xhrTimeout,
//loader: list.parent(),
success: function(data) {
var seen = 0;
success: function (data) {
let seen = 0;

if($.isEmptyObject(data.list)){
if ($.isEmptyObject(data.list)) {
list.find('.empty-row span').show();
}

$.each(data.list, function (index, object) {
if(list.find('>div[data-id="' + object.id + '"]').length){
if (list.find('>div[data-id="' + object.id + '"]').length) {
return;
}

var item = renderRow(object);
item.find('.mark-read').on('click', function(e) {
e.stopPropagation();
if(item.hasClass('read')){
return;
}
var mark = $(this);
$.ajax({
url: options.readUrl,
type: "GET",
data: {id: item.data('id')},
dataType: "json",
timeout: opts.xhrTimeout,
success: function (data) {
markRead(mark);
}
});
}).tooltip();
let item = renderRow(object);

if(object.url){
item.on('click', function(e) {
if (object.url) {
item.on('click', function (e) {
document.location = object.url;
});
}

if(object.seen == '0'){
if (object.seen == '0') {
seen += 1;
}

list.append(item);
});

initMarkReadButtons();

setCount(seen, true);

startPoll(true);
}
});
};

elem.find('> a[data-toggle="dropdown"]').on('click', function(e){
if(!$(this).parent().hasClass('show')){
elem.find('> a[data-toggle="dropdown"]').on('click', function (e) {
if (!$(this).parent().hasClass('show')) {
showList();
}
});

elem.find('.read-all').on('click', function(e){
elem.find('.read-all').on('click', function (e) {
e.stopPropagation();
var link = $(this);
let link = $(this);
$.ajax({
url: options.readAllUrl,
type: "GET",
dataType: "json",
type: 'GET',
dataType: 'json',
timeout: opts.xhrTimeout,
success: function (data) {
markRead(elem.find('.dropdown-item:not(.read)').find('.mark-read'));
link.off('click').on('click', function(){ return false; });
displayAsRead(elem.find('.dropdown-item:not(.read)').find('.mark-read'));
link.off('click').on('click', function () {
return false;
});
updateCount();
}
});
});

var markRead = function(mark){
mark.off('click').on('click', function(){ return false; });
/**
* Mark a notification as read.
* @param mark
*/
const displayAsRead = function (mark) {
mark.attr('title', options.readLabel);
mark.tooltip('dispose').tooltip();
mark.closest('.dropdown-item').addClass('read');
mark.closest('.notification-item').addClass('read');
};

/**
* Mark a notification as unread.
* @param mark
*/
const displayAsUnread = function (mark) {
mark.attr('title', options.markAsReadLabel);
mark.tooltip('dispose').tooltip();
mark.closest('.notification-item').removeClass('read');
};

var setCount = function(count, decrement) {
var badge = elem.find('.notifications-count');
if(decrement) {
const setCount = function (count, decrement) {
const badge = elem.find('.notifications-count');
if (decrement) {
count = parseInt(badge.data('count')) - count;
}

if(count > 0){
if (count > 0) {
badge.data('count', count).text(count).show();
}
else {
} else {
badge.data('count', 0).text(0).hide();
}
};

var updateCount = function() {
const updateCount = function () {
$.ajax({
url: options.countUrl,
type: "GET",
dataType: "json",
type: 'GET',
dataType: 'json',
timeout: opts.xhrTimeout,
success: function(data) {
success: function (data) {
setCount(data.count);
},
complete: function() {
complete: function () {
startPoll();
}
});
};

var _updateTimeout;
var startPoll = function(restart) {
if (restart && _updateTimeout){
let _updateTimeout;
const startPoll = function (restart) {
if (restart && _updateTimeout) {
clearTimeout(_updateTimeout);
}
_updateTimeout = setTimeout(function() {
_updateTimeout = setTimeout(function () {
updateCount();
}, opts.pollInterval);
};

// Fire the initial poll
startPoll();

initMarkReadButtons();
});
13 changes: 9 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
],
"license": "BSD-3-Clause",
"require": {
"php": ">=7.1",
"php": ">=8.1",
"yiisoft/yii2": "~2.0.13",
"minishlink/web-push": "^5.2"
"minishlink/web-push": "^8.0.0"
},
"autoload": {
"psr-4": {
Expand All @@ -35,5 +35,10 @@
"type": "composer",
"url": "https://asset-packagist.org"
}
]
}
],
"config": {
"allow-plugins": {
"yiisoft/yii2-composer": true
}
}
}
Loading