mirror of
https://github.com/discourse/discourse.git
synced 2025-01-31 15:17:14 +08:00
Convert to file in lib/, rough active tracking
This commit is contained in:
parent
41819838ef
commit
da9913359c
|
@ -1,162 +0,0 @@
|
|||
|
||||
// TODO deduplicate controllers/notification.js
|
||||
function notificationUrl(n) {
|
||||
const it = Em.Object.create(n);
|
||||
|
||||
var badgeId = it.get("data.badge_id");
|
||||
if (badgeId) {
|
||||
var badgeName = it.get("data.badge_name");
|
||||
return '/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase();
|
||||
}
|
||||
|
||||
var topicId = it.get('topic_id');
|
||||
if (topicId) {
|
||||
return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number"));
|
||||
}
|
||||
|
||||
if (it.get('notification_type') === INVITED_TYPE) {
|
||||
return '/my/invited';
|
||||
}
|
||||
}
|
||||
|
||||
export default Discourse.Controller.extend({
|
||||
|
||||
initSeenNotifications: function() {
|
||||
const self = this;
|
||||
|
||||
// TODO make protocol to elect a tab responsible for desktop notifications
|
||||
// and choose a new one when a tab is closed
|
||||
// apparently needs to use localStorage !?
|
||||
// https://github.com/diy/intercom.js
|
||||
|
||||
// Just causes a bit of a visual glitch as multiple are created and
|
||||
// instantly replaced as is
|
||||
self.set('primaryTab', true);
|
||||
|
||||
self.set('liveEnabled', false);
|
||||
this.requestPermission().then(function() {
|
||||
self.set('liveEnabled', true);
|
||||
}).catch(function() {
|
||||
self.set('liveEnabled', false);
|
||||
});
|
||||
|
||||
self.set('seenNotificationDates', {});
|
||||
Discourse.ajax("/notifications.json?silent=true").then(function(result) {
|
||||
self.updateSeenNotificationDatesFrom(result);
|
||||
});
|
||||
}.on('init'),
|
||||
|
||||
// Call-in point from message bus
|
||||
notificationsChanged(currentUser) {
|
||||
if (!this.get('liveEnabled')) { return; }
|
||||
if (!this.get('primaryTab')) { return; }
|
||||
|
||||
const blueNotifications = currentUser.get('unread_notifications');
|
||||
const greenNotifications = currentUser.get('unread_private_messages');
|
||||
const self = this;
|
||||
|
||||
if (blueNotifications > 0 || greenNotifications > 0) {
|
||||
Discourse.ajax("/notifications.json?silent=true").then(function(result) {
|
||||
|
||||
const unread = result.filter(n => !n.read);
|
||||
const unseen = self.updateSeenNotificationDatesFrom(result);
|
||||
const unreadCount = unread.length;
|
||||
const unseenCount = unseen.length;
|
||||
|
||||
if (unreadCount === 0 || unseenCount === 0) {
|
||||
return;
|
||||
}
|
||||
if (typeof document.hidden !== "undefined" && !document.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
let bodyParts = [];
|
||||
|
||||
unread.forEach(function(n) {
|
||||
const i18nOpts = {
|
||||
username: n.data['display_username'],
|
||||
topic: n.data['topic_title'],
|
||||
badge: n.data['badge_name']
|
||||
};
|
||||
|
||||
bodyParts.push(I18n.t(self.i18nKey(n), i18nOpts));
|
||||
});
|
||||
|
||||
const notificationTitle = I18n.t('notifications.popup_title', { count: unreadCount, site_title: Discourse.SiteSettings.title });
|
||||
const notificationBody = bodyParts.join("\n");
|
||||
const notificationIcon = Discourse.SiteSettings.logo_small_url || Discourse.SiteSettings.logo_url;
|
||||
const notificationTag = self.get('notificationTagName');
|
||||
|
||||
// This shows the notification!
|
||||
const notification = new Notification(notificationTitle, {
|
||||
body: notificationBody,
|
||||
icon: notificationIcon,
|
||||
tag: notificationTag
|
||||
});
|
||||
|
||||
const firstUnseen = unseen[0];
|
||||
|
||||
function clickEventHandler() {
|
||||
Discourse.URL.routeTo(notificationUrl(firstUnseen));
|
||||
// Cannot delay this until the page renders :(
|
||||
// due to trigger-based permissions
|
||||
window.focus();
|
||||
}
|
||||
|
||||
notification.addEventListener('click', clickEventHandler);
|
||||
setTimeout(function() {
|
||||
notification.close();
|
||||
notification.removeEventListener('click', clickEventHandler);
|
||||
}, 10 * 1000);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Utility function
|
||||
// Wraps Notification.requestPermission in a Promise
|
||||
requestPermission() {
|
||||
return new Ember.RSVP.Promise(function(resolve, reject) {
|
||||
Notification.requestPermission(function(status) {
|
||||
if (status === "granted") {
|
||||
Em.Logger.info('Discourse desktop notifications are enabled.');
|
||||
resolve();
|
||||
} else {
|
||||
Em.Logger.info('Discourse desktop notifications are disabled.');
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
i18nKey(notification) {
|
||||
let key = "notifications.popup." + this.site.get("notificationLookup")[notification.notification_type];
|
||||
if (notification.data.display_username && notification.data.original_username &&
|
||||
notification.data.display_username !== notification.data.original_username) {
|
||||
key += "_mul";
|
||||
}
|
||||
return key;
|
||||
},
|
||||
|
||||
notificationTagName: function() {
|
||||
return "discourse-notification-popup-" + Discourse.SiteSettings.title;
|
||||
}.property(),
|
||||
|
||||
// Utility function
|
||||
updateSeenNotificationDatesFrom(notifications) {
|
||||
const oldSeenNotificationDates = this.get('seenNotificationDates');
|
||||
let newSeenNotificationDates = {};
|
||||
let previouslyUnseenNotifications = [];
|
||||
|
||||
notifications.forEach(function(notification) {
|
||||
const dateString = new Date(notification.created_at).toUTCString();
|
||||
|
||||
if (!oldSeenNotificationDates[dateString]) {
|
||||
previouslyUnseenNotifications.push(notification);
|
||||
}
|
||||
newSeenNotificationDates[dateString] = true;
|
||||
});
|
||||
|
||||
this.set('seenNotificationDates', newSeenNotificationDates);
|
||||
return previouslyUnseenNotifications;
|
||||
}
|
||||
})
|
|
@ -1,4 +1,5 @@
|
|||
import ObjectController from 'discourse/controllers/object';
|
||||
import { notificationUrl } from 'discourse/lib/desktop-notifications';
|
||||
|
||||
var INVITED_TYPE= 8;
|
||||
|
||||
|
@ -10,36 +11,17 @@ const NotificationController = ObjectController.extend({
|
|||
|
||||
username: Em.computed.alias("data.display_username"),
|
||||
|
||||
safe(prop) {
|
||||
let val = this.get(prop);
|
||||
if (val) { val = Handlebars.Utils.escapeExpression(val); }
|
||||
return val;
|
||||
},
|
||||
|
||||
// This is model logic
|
||||
// It belongs in a model
|
||||
// TODO deduplicate controllers/background-notifications.js
|
||||
url: function() {
|
||||
const badgeId = this.safe("data.badge_id");
|
||||
if (badgeId) {
|
||||
const badgeName = this.safe("data.badge_name");
|
||||
return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase());
|
||||
}
|
||||
|
||||
const topicId = this.safe('topic_id');
|
||||
if (topicId) {
|
||||
return Discourse.Utilities.postUrl(this.safe("slug"), topicId, this.safe("post_number"));
|
||||
}
|
||||
|
||||
if (this.get('notification_type') === INVITED_TYPE) {
|
||||
return Discourse.getURL('/my/invited');
|
||||
}
|
||||
return notificationUrl(this);
|
||||
}.property("data.{badge_id,badge_name}", "slug", "topic_id", "post_number"),
|
||||
|
||||
description: function() {
|
||||
const badgeName = this.safe("data.badge_name");
|
||||
if (badgeName) { return badgeName; }
|
||||
return this.blank("data.topic_title") ? "" : this.safe("data.topic_title");
|
||||
const badgeName = this.get("data.badge_name");
|
||||
if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); }
|
||||
return this.blank("data.topic_title") ? "" : Handlebars.Utils.escapeExpression(this.get("data.topic_title"));
|
||||
}.property("data.{badge_name,topic_title}")
|
||||
|
||||
});
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Subscribes to user events on the message bus
|
||||
import { init as initDesktopNotifications, onNotification } from 'discourse/lib/desktop-notifications'
|
||||
|
||||
export default {
|
||||
name: 'subscribe-user-notifications',
|
||||
after: 'message-bus',
|
||||
|
@ -6,8 +8,7 @@ export default {
|
|||
const user = container.lookup('current-user:main'),
|
||||
site = container.lookup('site:main'),
|
||||
siteSettings = container.lookup('site-settings:main'),
|
||||
bus = container.lookup('message-bus:main'),
|
||||
bgController = container.lookup('controller:background-notifications');
|
||||
bus = container.lookup('message-bus:main');
|
||||
|
||||
bus.callbackInterval = siteSettings.anon_polling_interval;
|
||||
bus.backgroundCallbackInterval = siteSettings.background_polling_interval;
|
||||
|
@ -36,24 +37,26 @@ export default {
|
|||
user.set('post_queue_new_count', data.post_queue_new_count);
|
||||
});
|
||||
}
|
||||
bus.subscribe("/notification/" + user.get('id'), (function(data) {
|
||||
bus.subscribe("/notification/" + user.get('id'), function(data) {
|
||||
const oldUnread = user.get('unread_notifications');
|
||||
const oldPM = user.get('unread_private_messages');
|
||||
|
||||
user.set('unread_notifications', data.unread_notifications);
|
||||
user.set('unread_private_messages', data.unread_private_messages);
|
||||
|
||||
if(oldUnread !== data.unread_notifications || oldPM !== data.unread_private_messages) {
|
||||
if (oldUnread !== data.unread_notifications || oldPM !== data.unread_private_messages) {
|
||||
user.set('lastNotificationChange', new Date());
|
||||
bgController.notificationsChanged(user);
|
||||
onNotification(user);
|
||||
}
|
||||
}), user.notification_channel_position);
|
||||
}, user.notification_channel_position);
|
||||
|
||||
bus.subscribe("/categories", function(data){
|
||||
_.each(data.categories,function(c){
|
||||
site.updateCategory(c);
|
||||
});
|
||||
});
|
||||
|
||||
initDesktopNotifications(container);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
|
||||
let primaryTab;
|
||||
let liveEnabled;
|
||||
let seenNotificationDates = {};
|
||||
let notificationTagName;
|
||||
let mbClientId;
|
||||
|
||||
const focusTrackerKey = "focus-tracker";
|
||||
|
||||
function init(container) {
|
||||
liveEnabled = false;
|
||||
requestPermission().then(function () {
|
||||
try {
|
||||
localStorage.getItem(focusTrackerKey);
|
||||
} catch (e) {
|
||||
liveEnabled = false;
|
||||
Em.Logger.info('Discourse desktop notifications are disabled - localStorage denied.');
|
||||
return;
|
||||
}
|
||||
liveEnabled = true;
|
||||
Em.Logger.info('Discourse desktop notifications are enabled.');
|
||||
|
||||
init2(container);
|
||||
|
||||
}).catch(function () {
|
||||
liveEnabled = false;
|
||||
Em.Logger.info('Discourse desktop notifications are disabled - permission denied.');
|
||||
});
|
||||
}
|
||||
|
||||
function init2(container) {
|
||||
// Load up the current state of the notifications
|
||||
seenNotificationDates = {};
|
||||
Discourse.ajax("/notifications.json?silent=true").then(function(result) {
|
||||
updateSeenNotificationDatesFrom(result);
|
||||
});
|
||||
|
||||
notificationTagName = "discourse-notification-popup-" + Discourse.SiteSettings.title;
|
||||
|
||||
const messageBus = container.lookup('message-bus:main');
|
||||
mbClientId = messageBus.clientId;
|
||||
|
||||
console.info("My client ID is", mbClientId);
|
||||
|
||||
window.addEventListener("storage", function(e) {
|
||||
// note: This event only fires when other tabs setItem()
|
||||
const key = e.key;
|
||||
if (key !== focusTrackerKey) {
|
||||
return true;
|
||||
}
|
||||
if (primaryTab) {
|
||||
primaryTab = false;
|
||||
console.debug("Releasing focus to", e.oldValue);
|
||||
}
|
||||
});
|
||||
window.addEventListener("focus", function() {
|
||||
if (!primaryTab) {
|
||||
console.debug("Grabbing focus from", localStorage.getItem(focusTrackerKey));
|
||||
primaryTab = true;
|
||||
localStorage.setItem(focusTrackerKey, mbClientId);
|
||||
}
|
||||
});
|
||||
|
||||
if (document.hidden) {
|
||||
primaryTab = false;
|
||||
} else {
|
||||
primaryTab = true;
|
||||
localStorage.setItem(focusTrackerKey, mbClientId);
|
||||
console.debug("Grabbing focus");
|
||||
}
|
||||
}
|
||||
|
||||
// Call-in point from message bus
|
||||
function onNotification(currentUser) {
|
||||
if (!liveEnabled) { return; }
|
||||
if (!primaryTab) { return; }
|
||||
|
||||
const blueNotifications = currentUser.get('unread_notifications');
|
||||
const greenNotifications = currentUser.get('unread_private_messages');
|
||||
|
||||
if (blueNotifications > 0 || greenNotifications > 0) {
|
||||
Discourse.ajax("/notifications.json?silent=true").then(function(result) {
|
||||
|
||||
const unread = result.filter(n => !n.read);
|
||||
const unseen = updateSeenNotificationDatesFrom(result);
|
||||
const unreadCount = unread.length;
|
||||
const unseenCount = unseen.length;
|
||||
|
||||
if (unreadCount === 0 || unseenCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let bodyParts = [];
|
||||
|
||||
unread.forEach(function(n) {
|
||||
const i18nOpts = {
|
||||
username: n.data['display_username'],
|
||||
topic: n.data['topic_title'],
|
||||
badge: n.data['badge_name']
|
||||
};
|
||||
|
||||
bodyParts.push(I18n.t(i18nKey(n), i18nOpts));
|
||||
});
|
||||
|
||||
const notificationTitle = I18n.t('notifications.popup_title', { count: unreadCount, site_title: Discourse.SiteSettings.title });
|
||||
const notificationBody = bodyParts.join("\n");
|
||||
const notificationIcon = Discourse.SiteSettings.logo_small_url || Discourse.SiteSettings.logo_url;
|
||||
|
||||
// This shows the notification!
|
||||
const notification = new Notification(notificationTitle, {
|
||||
body: notificationBody,
|
||||
icon: notificationIcon,
|
||||
tag: notificationTagName
|
||||
});
|
||||
|
||||
const firstUnseen = unseen[0];
|
||||
|
||||
function clickEventHandler() {
|
||||
Discourse.URL.routeTo(_notificationUrl(firstUnseen));
|
||||
// Cannot delay this until the page renders :(
|
||||
// due to trigger-based permissions
|
||||
window.focus();
|
||||
}
|
||||
|
||||
notification.addEventListener('click', clickEventHandler);
|
||||
setTimeout(function() {
|
||||
notification.close();
|
||||
notification.removeEventListener('click', clickEventHandler);
|
||||
}, 10 * 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function
|
||||
// Wraps Notification.requestPermission in a Promise
|
||||
function requestPermission() {
|
||||
return new Ember.RSVP.Promise(function(resolve, reject) {
|
||||
Notification.requestPermission(function(status) {
|
||||
if (status === "granted") {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function i18nKey(notification) {
|
||||
let key = "notifications.popup." + Discourse.Site.current().get("notificationLookup")[notification.notification_type];
|
||||
if (notification.data.display_username && notification.data.original_username &&
|
||||
notification.data.display_username !== notification.data.original_username) {
|
||||
key += "_mul";
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// Utility function
|
||||
function updateSeenNotificationDatesFrom(notifications) {
|
||||
const oldSeenNotificationDates = seenNotificationDates;
|
||||
let newSeenNotificationDates = {};
|
||||
let previouslyUnseenNotifications = [];
|
||||
|
||||
notifications.forEach(function(notification) {
|
||||
const dateString = new Date(notification.created_at).toUTCString();
|
||||
|
||||
if (!oldSeenNotificationDates[dateString]) {
|
||||
previouslyUnseenNotifications.push(notification);
|
||||
}
|
||||
newSeenNotificationDates[dateString] = true;
|
||||
});
|
||||
|
||||
seenNotificationDates = newSeenNotificationDates;
|
||||
return previouslyUnseenNotifications;
|
||||
}
|
||||
|
||||
// Exported for controllers/notification.js.es6
|
||||
function notificationUrl(it) {
|
||||
var badgeId = it.get("data.badge_id");
|
||||
if (badgeId) {
|
||||
var badgeName = it.get("data.badge_name");
|
||||
return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase());
|
||||
}
|
||||
|
||||
var topicId = it.get('topic_id');
|
||||
if (topicId) {
|
||||
return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number"));
|
||||
}
|
||||
|
||||
if (it.get('notification_type') === INVITED_TYPE) {
|
||||
return Discourse.getURL('/my/invited');
|
||||
}
|
||||
}
|
||||
|
||||
function _notificationUrl(notificationJson) {
|
||||
const it = Em.Object.create(notificationJson);
|
||||
return notificationUrl(it);
|
||||
}
|
||||
|
||||
export { init, notificationUrl, onNotification };
|
|
@ -66,6 +66,7 @@
|
|||
//= require ./discourse/dialects/dialect
|
||||
//= require ./discourse/lib/emoji/emoji
|
||||
//= require ./discourse/lib/sharing
|
||||
//= require discourse/lib/desktop-notifications
|
||||
|
||||
//= require_tree ./discourse/dialects
|
||||
//= require_tree ./discourse/controllers
|
||||
|
|
Loading…
Reference in New Issue
Block a user