2016-02-29 21:58:01 +01:00
|
|
|
// Converse.js (A browser based XMPP chat client)
|
|
|
|
// http://conversejs.org
|
|
|
|
//
|
2017-02-13 15:37:17 +01:00
|
|
|
// Copyright (c) 2012-2017, Jan-Carel Brand <jc@opkode.com>
|
2016-02-29 21:58:01 +01:00
|
|
|
// Licensed under the Mozilla Public License (MPLv2)
|
|
|
|
//
|
|
|
|
/*global define */
|
|
|
|
|
|
|
|
(function (root, factory) {
|
2017-02-14 15:08:39 +01:00
|
|
|
define(["converse-core"], factory);
|
2016-12-20 11:42:20 +01:00
|
|
|
}(this, function (converse) {
|
2016-02-29 21:58:01 +01:00
|
|
|
"use strict";
|
2017-07-10 17:46:22 +02:00
|
|
|
const { utils, Strophe, _ } = converse.env;
|
2016-02-29 21:58:01 +01:00
|
|
|
|
2016-12-20 11:42:20 +01:00
|
|
|
converse.plugins.add('converse-notification', {
|
2016-02-29 21:58:01 +01:00
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
initialize () {
|
2016-02-29 21:58:01 +01:00
|
|
|
/* The initialize function gets called as soon as the plugin is
|
|
|
|
* loaded by converse.js's plugin machinery.
|
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
const { _converse } = this;
|
2016-12-20 11:42:20 +01:00
|
|
|
|
2016-12-20 11:42:20 +01:00
|
|
|
// For translations
|
2017-07-10 17:46:22 +02:00
|
|
|
const { __ } = _converse;
|
|
|
|
const { ___ } = _converse;
|
2016-12-20 11:42:20 +01:00
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.supports_html5_notification = "Notification" in window;
|
2016-03-13 17:22:42 +01:00
|
|
|
|
2017-07-05 11:03:13 +02:00
|
|
|
_converse.api.settings.update({
|
2016-06-16 10:56:32 +02:00
|
|
|
notify_all_room_messages: false,
|
2016-03-01 10:43:44 +01:00
|
|
|
show_desktop_notifications: true,
|
2017-02-14 14:00:45 +01:00
|
|
|
show_chatstate_notifications: false,
|
2016-03-18 10:10:14 +01:00
|
|
|
chatstate_notification_blacklist: [],
|
|
|
|
// ^ a list of JIDs to ignore concerning chat state notifications
|
2017-02-27 11:09:15 +01:00
|
|
|
play_sounds: true,
|
2016-03-01 09:58:36 +01:00
|
|
|
sounds_path: '/sounds/',
|
2016-07-02 13:40:51 +02:00
|
|
|
notification_icon: '/logo/conversejs128.png'
|
2016-03-13 17:22:42 +01:00
|
|
|
});
|
|
|
|
|
2017-07-10 17:46:22 +02:00
|
|
|
_converse.isOnlyChatStateNotification = (msg) =>
|
2016-03-01 09:58:36 +01:00
|
|
|
// See XEP-0085 Chat State Notification
|
2017-07-10 17:46:22 +02:00
|
|
|
_.isNull(msg.querySelector('body')) && (
|
2017-02-24 16:10:22 +01:00
|
|
|
_.isNull(msg.querySelector(_converse.ACTIVE)) ||
|
|
|
|
_.isNull(msg.querySelector(_converse.COMPOSING)) ||
|
|
|
|
_.isNull(msg.querySelector(_converse.INACTIVE)) ||
|
|
|
|
_.isNull(msg.querySelector(_converse.PAUSED)) ||
|
|
|
|
_.isNull(msg.querySelector(_converse.GONE))
|
2016-03-01 09:58:36 +01:00
|
|
|
)
|
2017-07-10 17:46:22 +02:00
|
|
|
;
|
2016-03-01 09:58:36 +01:00
|
|
|
|
2017-02-24 16:10:22 +01:00
|
|
|
_converse.shouldNotifyOfGroupMessage = function (message) {
|
2016-03-08 11:42:52 +01:00
|
|
|
/* Is this a group message worthy of notification?
|
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
let notify_all = _converse.notify_all_room_messages;
|
|
|
|
const jid = message.getAttribute('from'),
|
2016-03-08 11:42:52 +01:00
|
|
|
resource = Strophe.getResourceFromJid(jid),
|
2016-06-16 17:24:58 +02:00
|
|
|
room_jid = Strophe.getBareJidFromJid(jid),
|
2016-03-08 11:42:52 +01:00
|
|
|
sender = resource && Strophe.unescapeNode(resource) || '';
|
2017-02-24 16:10:22 +01:00
|
|
|
if (sender === '' || message.querySelectorAll('delay').length > 0) {
|
2016-03-08 11:42:52 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const room = _converse.chatboxes.get(room_jid);
|
|
|
|
const body = message.querySelector('body');
|
2017-02-24 16:10:22 +01:00
|
|
|
if (_.isNull(body)) {
|
2016-06-17 11:33:09 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const mentioned = (new RegExp(`\\b${room.get('nick')}\\b`)).test(body.textContent);
|
2017-02-24 16:10:22 +01:00
|
|
|
notify_all = notify_all === true ||
|
|
|
|
(_.isArray(notify_all) && _.includes(notify_all, room_jid));
|
2016-06-16 10:56:32 +02:00
|
|
|
if (sender === room.get('nick') || (!notify_all && !mentioned)) {
|
2016-03-08 11:42:52 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.shouldNotifyOfMessage = function (message) {
|
2016-03-08 11:42:52 +01:00
|
|
|
/* Is this a message worthy of notification?
|
|
|
|
*/
|
2016-05-30 20:19:10 +02:00
|
|
|
if (utils.isOTRMessage(message)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const forwarded = message.querySelector('forwarded');
|
2017-02-24 16:10:22 +01:00
|
|
|
if (!_.isNull(forwarded)) {
|
2016-03-01 09:58:36 +01:00
|
|
|
return false;
|
2017-02-24 16:10:22 +01:00
|
|
|
} else if (message.getAttribute('type') === 'groupchat') {
|
|
|
|
return _converse.shouldNotifyOfGroupMessage(message);
|
2016-03-28 12:49:52 +02:00
|
|
|
} else if (utils.isHeadlineMessage(message)) {
|
2016-03-22 09:45:54 +01:00
|
|
|
// We want to show notifications for headline messages.
|
|
|
|
return true;
|
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const is_me = Strophe.getBareJidFromJid(
|
2017-02-24 16:10:22 +01:00
|
|
|
message.getAttribute('from')) === _converse.bare_jid;
|
|
|
|
return !_converse.isOnlyChatStateNotification(message) && !is_me;
|
2016-03-01 09:58:36 +01:00
|
|
|
};
|
|
|
|
|
2017-02-24 16:10:22 +01:00
|
|
|
_converse.playSoundNotification = function () {
|
2016-03-01 09:58:36 +01:00
|
|
|
/* Plays a sound to notify that a new message was recieved.
|
|
|
|
*/
|
|
|
|
// XXX Eventually this can be refactored to use Notification's sound
|
|
|
|
// feature, but no browser currently supports it.
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/notification/sound
|
2017-07-10 17:46:22 +02:00
|
|
|
let audio;
|
2017-02-27 11:09:15 +01:00
|
|
|
if (_converse.play_sounds && !_.isUndefined(window.Audio)) {
|
2016-12-20 10:30:20 +01:00
|
|
|
audio = new Audio(_converse.sounds_path+"msg_received.ogg");
|
2016-03-01 09:58:36 +01:00
|
|
|
if (audio.canPlayType('/audio/ogg')) {
|
|
|
|
audio.play();
|
|
|
|
} else {
|
2016-12-20 10:30:20 +01:00
|
|
|
audio = new Audio(_converse.sounds_path+"msg_received.mp3");
|
2016-03-01 09:58:36 +01:00
|
|
|
audio.play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2016-02-29 21:58:01 +01:00
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.areDesktopNotificationsEnabled = function (ignore_hidden) {
|
2017-07-10 17:46:22 +02:00
|
|
|
const enabled = _converse.supports_html5_notification &&
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.show_desktop_notifications &&
|
2016-03-08 12:01:23 +01:00
|
|
|
Notification.permission === "granted";
|
2016-06-17 11:30:47 +02:00
|
|
|
if (ignore_hidden) {
|
2016-03-08 12:01:23 +01:00
|
|
|
return enabled;
|
|
|
|
} else {
|
2016-12-20 10:30:20 +01:00
|
|
|
return enabled && _converse.windowState === 'hidden';
|
2016-03-08 12:01:23 +01:00
|
|
|
}
|
2016-03-08 11:42:52 +01:00
|
|
|
};
|
|
|
|
|
2017-02-24 16:10:22 +01:00
|
|
|
_converse.showMessageNotification = function (message) {
|
2016-03-08 09:44:45 +01:00
|
|
|
/* Shows an HTML5 Notification to indicate that a new chat
|
|
|
|
* message was received.
|
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
let title, roster_item;
|
|
|
|
const full_from_jid = message.getAttribute('from'),
|
|
|
|
from_jid = Strophe.getBareJidFromJid(full_from_jid);
|
2017-02-24 16:10:54 +01:00
|
|
|
if (message.getAttribute('type') === 'headline') {
|
|
|
|
if (!_.includes(from_jid, '@') || _converse.allow_non_roster_messaging) {
|
|
|
|
title = __(___("Notification from %1$s"), from_jid);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (!_.includes(from_jid, '@')) {
|
|
|
|
// XXX: workaround for Prosody which doesn't give type "headline"
|
2016-03-22 09:45:54 +01:00
|
|
|
title = __(___("Notification from %1$s"), from_jid);
|
2017-02-24 16:10:54 +01:00
|
|
|
} else if (message.getAttribute('type') === 'groupchat') {
|
2017-04-19 16:05:31 +02:00
|
|
|
title = __(___("%1$s says"), Strophe.getResourceFromJid(full_from_jid));
|
2016-03-22 09:45:54 +01:00
|
|
|
} else {
|
2017-02-24 16:10:54 +01:00
|
|
|
if (_.isUndefined(_converse.roster)) {
|
|
|
|
_converse.log(
|
|
|
|
"Could not send notification, because roster is undefined",
|
2017-07-05 11:33:55 +02:00
|
|
|
Strophe.LogLevel.ERROR);
|
2017-02-24 16:10:54 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
roster_item = _converse.roster.get(from_jid);
|
|
|
|
if (!_.isUndefined(roster_item)) {
|
|
|
|
title = __(___("%1$s says"), roster_item.get('fullname'));
|
2016-04-28 16:51:50 +02:00
|
|
|
} else {
|
2017-02-24 16:10:54 +01:00
|
|
|
if (_converse.allow_non_roster_messaging) {
|
|
|
|
title = __(___("%1$s says"), from_jid);
|
|
|
|
} else {
|
2016-04-28 16:51:50 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-03-22 09:45:54 +01:00
|
|
|
}
|
2016-03-21 11:40:47 +01:00
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const n = new Notification(title, {
|
2017-02-24 16:10:22 +01:00
|
|
|
body: message.querySelector('body').textContent,
|
2017-04-19 14:18:30 +02:00
|
|
|
lang: _converse.locale,
|
2016-12-20 10:30:20 +01:00
|
|
|
icon: _converse.notification_icon
|
2016-03-08 09:44:45 +01:00
|
|
|
});
|
|
|
|
setTimeout(n.close.bind(n), 5000);
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.showChatStateNotification = function (contact) {
|
2016-03-08 11:42:52 +01:00
|
|
|
/* Creates an HTML5 Notification to inform of a change in a
|
|
|
|
* contact's chat state.
|
2016-02-29 22:59:56 +01:00
|
|
|
*/
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_.includes(_converse.chatstate_notification_blacklist, contact.jid)) {
|
2016-03-18 10:10:14 +01:00
|
|
|
// Don't notify if the user is being ignored.
|
|
|
|
return;
|
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const chat_state = contact.chat_status;
|
|
|
|
let message = null;
|
2016-02-29 22:59:56 +01:00
|
|
|
if (chat_state === 'offline') {
|
|
|
|
message = __('has gone offline');
|
|
|
|
} else if (chat_state === 'away') {
|
|
|
|
message = __('has gone away');
|
|
|
|
} else if ((chat_state === 'dnd')) {
|
|
|
|
message = __('is busy');
|
|
|
|
} else if (chat_state === 'online') {
|
|
|
|
message = __('has come online');
|
|
|
|
}
|
|
|
|
if (message === null) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-10 17:46:22 +02:00
|
|
|
const n = new Notification(contact.fullname, {
|
2016-02-29 22:59:56 +01:00
|
|
|
body: message,
|
2017-04-19 14:18:30 +02:00
|
|
|
lang: _converse.locale,
|
2017-02-15 20:12:45 +01:00
|
|
|
icon: _converse.notification_icon
|
2016-02-29 22:59:56 +01:00
|
|
|
});
|
|
|
|
setTimeout(n.close.bind(n), 5000);
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.showContactRequestNotification = function (contact) {
|
2017-07-10 17:46:22 +02:00
|
|
|
const n = new Notification(contact.fullname, {
|
2016-03-08 13:16:04 +01:00
|
|
|
body: __('wants to be your contact'),
|
2017-04-19 14:18:30 +02:00
|
|
|
lang: _converse.locale,
|
2017-02-15 20:12:45 +01:00
|
|
|
icon: _converse.notification_icon
|
2016-03-08 12:01:23 +01:00
|
|
|
});
|
|
|
|
setTimeout(n.close.bind(n), 5000);
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.showFeedbackNotification = function (data) {
|
2016-08-23 13:35:16 +02:00
|
|
|
if (data.klass === 'error' || data.klass === 'warn') {
|
2017-07-10 17:46:22 +02:00
|
|
|
const n = new Notification(data.subject, {
|
2016-08-23 13:35:16 +02:00
|
|
|
body: data.message,
|
2017-04-19 14:18:30 +02:00
|
|
|
lang: _converse.locale,
|
2017-02-15 20:12:45 +01:00
|
|
|
icon: _converse.notification_icon
|
2016-08-23 13:35:16 +02:00
|
|
|
});
|
|
|
|
setTimeout(n.close.bind(n), 5000);
|
|
|
|
}
|
2016-03-31 14:23:05 +02:00
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.handleChatStateNotification = function (contact) {
|
2016-03-08 11:42:52 +01:00
|
|
|
/* Event handler for on('contactStatusChanged').
|
|
|
|
* Will show an HTML5 notification to indicate that the chat
|
|
|
|
* status has changed.
|
|
|
|
*/
|
2017-02-24 16:10:22 +01:00
|
|
|
if (_converse.areDesktopNotificationsEnabled() &&
|
|
|
|
_converse.show_chatstate_notifications) {
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.showChatStateNotification(contact);
|
2016-03-08 11:42:52 +01:00
|
|
|
}
|
|
|
|
};
|
2016-03-01 09:58:36 +01:00
|
|
|
|
2017-04-20 21:25:58 +02:00
|
|
|
_converse.handleMessageNotification = function (data) {
|
2016-03-01 09:58:36 +01:00
|
|
|
/* Event handler for the on('message') event. Will call methods
|
|
|
|
* to play sounds and show HTML5 notifications.
|
|
|
|
*/
|
2017-07-10 17:46:22 +02:00
|
|
|
const message = data.stanza;
|
2016-12-20 10:30:20 +01:00
|
|
|
if (!_converse.shouldNotifyOfMessage(message)) {
|
2016-03-01 09:58:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-02-24 16:10:22 +01:00
|
|
|
_converse.playSoundNotification();
|
2016-12-20 10:30:20 +01:00
|
|
|
if (_converse.areDesktopNotificationsEnabled()) {
|
2017-02-24 16:10:22 +01:00
|
|
|
_converse.showMessageNotification(message);
|
2016-03-08 11:42:52 +01:00
|
|
|
}
|
2016-03-01 09:58:36 +01:00
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.handleContactRequestNotification = function (contact) {
|
|
|
|
if (_converse.areDesktopNotificationsEnabled(true)) {
|
|
|
|
_converse.showContactRequestNotification(contact);
|
2016-03-08 12:01:23 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.handleFeedback = function (data) {
|
|
|
|
if (_converse.areDesktopNotificationsEnabled(true)) {
|
|
|
|
_converse.showFeedbackNotification(data);
|
2016-03-31 14:23:05 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.requestPermission = function () {
|
|
|
|
if (_converse.supports_html5_notification &&
|
2017-01-26 15:49:02 +01:00
|
|
|
! _.includes(['denied', 'granted'], Notification.permission)) {
|
2016-03-08 23:36:13 +01:00
|
|
|
// Ask user to enable HTML5 notifications
|
|
|
|
Notification.requestPermission();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.on('pluginsInitialized', function () {
|
2016-06-16 17:21:11 +02:00
|
|
|
// We only register event handlers after all plugins are
|
|
|
|
// registered, because other plugins might override some of our
|
|
|
|
// handlers.
|
2016-12-20 10:30:20 +01:00
|
|
|
_converse.on('contactRequest', _converse.handleContactRequestNotification);
|
|
|
|
_converse.on('contactStatusChanged', _converse.handleChatStateNotification);
|
|
|
|
_converse.on('message', _converse.handleMessageNotification);
|
|
|
|
_converse.on('feedback', _converse.handleFeedback);
|
|
|
|
_converse.on('connected', _converse.requestPermission);
|
2016-06-16 17:21:11 +02:00
|
|
|
});
|
2016-02-29 21:58:01 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}));
|