diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less
index ec0e3aa60..0cecd179f 100644
--- a/customize.dist/src/less2/include/toolbar.less
+++ b/customize.dist/src/less2/include/toolbar.less
@@ -898,6 +898,27 @@
}
.cp-toolbar-notifications {
margin-left: 10px;
+ .cp-notifications-empty {
+ color: black;
+ padding: 5px;
+ }
+ button {
+ position: relative;
+ &.fa-bell-o {
+ cursor: default;
+ }
+ .cp-dropdown-button-title {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ font-size: 14px;
+ border: 1px solid;
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ line-height: 16px;
+ }
+ }
}
.cp-toolbar-link {
display: inline-flex;
diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js
index a53f0c3b2..d8cf76c43 100644
--- a/www/common/common-messaging.js
+++ b/www/common/common-messaging.js
@@ -59,7 +59,6 @@ define([
curvePublic: data.curvePublic
}, function (obj) {
cb(obj);
- if (obj && obj.error) { return void cb(obj); }
});
};
Msg.addToFriendList = function (cfg, data, cb) {
diff --git a/www/common/common-messenger.js b/www/common/common-messenger.js
index c333112d9..f34c177ca 100644
--- a/www/common/common-messenger.js
+++ b/www/common/common-messenger.js
@@ -68,7 +68,7 @@ define([
});
};
- Msg.messenger = function (store) {
+ Msg.messenger = function (store, updateMetadata) {
var messenger = {
handlers: {
event: []
@@ -97,6 +97,7 @@ define([
stack.push(f);
};
+ var allowFriendsChannels = false;
var channels = messenger.channels = {};
var joining = {};
@@ -301,7 +302,10 @@ define([
if (!proxy.friends) { return; }
var friends = proxy.friends;
delete friends[curvePublic];
- Realtime.whenRealtimeSyncs(realtime, cb);
+ Realtime.whenRealtimeSyncs(realtime, function () {
+ updateMetadata();
+ cb();
+ });
};
var pushMsg = function (channel, cryptMsg) {
@@ -771,45 +775,9 @@ define([
openChannel(data);
};
- // Detect friends changes made in another worker
- proxy.on('change', ['friends'], function (o, n, p) {
- var curvePublic;
- if (o === undefined) {
- // new friend added
- curvePublic = p.slice(-1)[0];
-
- // Load channel
- var friend = friends[curvePublic];
- if (typeof(friend) !== 'object') { return; }
- var channel = friend.channel;
- if (!channel) { return; }
- loadFriend(friend, function () {
- emit('FRIEND', {
- curvePublic: curvePublic,
- });
- });
- return;
- }
-
- if (typeof(n) === 'undefined') {
- // Handled by .on('remove')
- return;
- }
- }).on('remove', ['friends'], function (o, p) {
- var curvePublic = p[1];
- if (!curvePublic) { return; }
- if (p[2] !== 'channel') { return; }
- var channel = channels[o];
- channel.wc.leave(Types.unfriend);
- delete channels[channel.id];
- emit('UNFRIEND', {
- curvePublic: curvePublic,
- fromMe: true
- });
- });
-
// Friend added in our contacts in the current worker
messenger.onFriendAdded = function (friendData) {
+ if (!allowFriendsChannels) { return; }
var friend = friends[friendData.curvePublic];
if (typeof(friend) !== 'object') { return; }
var channel = friend.channel;
@@ -820,10 +788,23 @@ define([
});
});
};
+ messenger.onFriendRemoved = function (curvePublic, chanId) {
+ var channel = channels[chanId];
+ if (!channel) { return; }
+ if (channel.wc) {
+ channel.wc.leave(Types.unfriend);
+ }
+ delete channels[channel.id];
+ emit('UNFRIEND', {
+ curvePublic: curvePublic,
+ fromMe: true
+ });
+ };
var ready = false;
var initialized = false;
var init = function () {
+ allowFriendsChannels = true;
if (initialized) { return; }
initialized = true;
var friends = getFriendList(proxy);
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index 3ba27f86f..aead1bcfd 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -2610,7 +2610,8 @@ define([
UIElements.displayFriendRequestModal = function (common, data) {
var msg = data.content.msg;
var text = Messages._getKey('contacts_request', [msg.content.displayName]);
- UI.confirm(text, function (yes) {
+
+ var todo = function (yes) {
common.getSframeChannel().query("Q_ANSWER_FRIEND_REQUEST", {
data: data,
value: yes
@@ -2621,10 +2622,32 @@ define([
}
UI.log(Messages.contacts_added);
});
+ };
+
+ var content = h('div.cp-share-modal', [
+ setHTML(h('p'), text)
+ ]);
+ var buttons = [{
+ name: Messages.cancel, // XXX "later"?
+ onClick: function () {},
+ keys: [27]
}, {
- ok: 'Accept', // XXX
- cancel: 'Ignore the request' // XXX
- }, true);
+ className: 'primary',
+ name: "Accept (Enter)", // XXX
+ onClick: function () {
+ todo(true);
+ },
+ keys: [13]
+ }, {
+ className: 'primary',
+ name: "Ignore the request", // XXX
+ onClick: function () {
+ todo(false);
+ },
+ keys: [[13, 'ctrl']]
+ }];
+ var modal = UI.dialog.customModal(content, {buttons: buttons});
+ UI.openCustomModal(modal);
};
return UIElements;
diff --git a/www/common/notifications.js b/www/common/notifications.js
new file mode 100644
index 000000000..570795efc
--- /dev/null
+++ b/www/common/notifications.js
@@ -0,0 +1,50 @@
+define([
+ 'jquery',
+ '/common/hyperscript.js',
+ '/common/common-ui-elements.js'
+], function ($, h, UIElements) {
+
+ var handlers = {};
+
+ handlers['FRIEND_REQUEST'] = function (common, data, el) {
+ var content = data.content;
+ var msg = content.msg;
+
+ // Check authenticity
+ if (msg.author !== msg.content.curvePublic) { return; }
+
+ common.addFriendRequest(data);
+
+ // Display the notification
+ $(el).find('.cp-notification-dismiss').attr('title', 'IGNORE').css('display', 'flex'); // XXX
+ $(el).find('.cp-notification-content').addClass("cp-clickable");
+ $(el).find('.cp-notification-content p')
+ .html('New friend request: '+msg.content.displayName+'') // XXX
+ .click(function () {
+ UIElements.displayFriendRequestModal(common, data);
+ });
+ };
+
+ handlers['ACCEPT_FRIEND_REQUEST'] = function (common, data, el) {
+ var content = data.content;
+ var msg = content.msg;
+ $(el).find('.cp-notification-content p')
+ .html('Friend request accepted: '+msg.content.displayName+'');
+ $(el).find('.cp-notification-dismiss').css('display', 'flex');
+ };
+
+ return {
+ add: function (common, data, el) {
+ var type = data.content.msg.type;
+
+ if (handlers[type]) {
+ handlers[type](common, data, el);
+ } else {
+ $(el).find('.cp-notification-dismiss').css('display', 'flex');
+ }
+ },
+ remove: function (common, data) {
+ common.removeFriendRequest(data.hash);
+ },
+ };
+});
diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js
index bcf3685ec..0e0d6fe68 100644
--- a/www/common/outer/async-store.js
+++ b/www/common/outer/async-store.js
@@ -639,7 +639,7 @@ define([
/*store.mailbox.post('notifications', 'NAME_CHANGED', {
old: store.proxy[Constants.displayNameKey],
new: value
- });*/
+ });
Object.keys(store.proxy.friends).forEach(function (curve) {
var f = store.proxy.friends[curve];
if (!f.notifications) { return; }
@@ -653,7 +653,7 @@ define([
if (obj && obj.error) { return void console.error(obj.error); }
console.log('notif sent to '+f);
});
- });
+ });*/
}
store.proxy[Constants.displayNameKey] = value;
broadcast([clientId], "UPDATE_METADATA");
@@ -911,7 +911,6 @@ define([
// Messaging (manage friends from the userlist)
Store.answerFriendRequest = function (clientId, obj, cb) {
- console.log(obj);
var value = obj.value;
var data = obj.data;
if (data.type !== 'notifications') { return void cb ({error: 'EINVAL'}); }
@@ -926,6 +925,7 @@ define([
}, cb);
};
+ // If we accept the request, add the friend to the list
if (value) {
Messaging.acceptFriendRequest(store, msg.content, function (obj) {
if (obj && obj.error) { return void cb(obj); }
@@ -934,6 +934,9 @@ define([
realtime: store.realtime,
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
}, msg.content, function (err) {
+ if (store.messenger) {
+ store.messenger.onFriendAdded(msg.content);
+ }
broadcast([], "UPDATE_METADATA");
if (err) { return void cb({error: err}); }
dismiss(cb);
@@ -941,6 +944,7 @@ define([
});
return;
}
+ // Otherwise, just remove the notification
dismiss();
};
Store.sendFriendRequest = function (clientId, data, cb) {
@@ -1445,7 +1449,9 @@ define([
};
var loadMessenger = function () {
if (AppConfig.availablePadTypes.indexOf('contacts') === -1) { return; }
- var messenger = store.messenger = Messenger.messenger(store);
+ var messenger = store.messenger = Messenger.messenger(store, function () {
+ broadcast([], "UPDATE_METADATA");
+ });
messenger.on('event', function (ev, data) {
sendMessengerEvent('CHAT_EVENT', {
ev: ev,
@@ -1496,6 +1502,18 @@ define([
});
};
+ var cleanFriendRequests = function () {
+ try {
+ if (!store.proxy.friends_pending) { return; }
+ var twoDaysAgo = +new Date() - (2 * 24 * 3600 * 1000); // XXX
+ Object.keys(store.proxy.friends_pending).forEach(function (curve) {
+ if (store.proxy.friends_pending[curve] < twoDaysAgo) {
+ delete store.proxy.friends_pending[curve];
+ }
+ });
+ } catch (e) {}
+ };
+
//////////////////////////////////////////////////////////////////
/////////////////////// Init /////////////////////////////////////
//////////////////////////////////////////////////////////////////
@@ -1591,6 +1609,7 @@ define([
loadCursor();
loadOnlyOffice();
loadMailbox(waitFor);
+ cleanFriendRequests();
}).nThen(function () {
var requestLogin = function () {
broadcast([], "REQUEST_LOGIN");
@@ -1644,14 +1663,32 @@ define([
// Trigger userlist update when the avatar has changed
broadcast([], "UPDATE_METADATA");
});
- proxy.on('change', ['friends'], function () {
+ proxy.on('change', ['friends'], function (o, n, p) {
// Trigger userlist update when the friendlist has changed
broadcast([], "UPDATE_METADATA");
+
+ if (!store.messenger) { return; }
+ if (o !== undefined) { return; }
+ var curvePublic = p.slice(-1)[0];
+ var friend = proxy.friends && proxy.friends[curvePublic];
+ store.messenger.onFriendAdded(friend);
+ });
+ proxy.on('remove', ['friends'], function (o, p) {
+ broadcast([], "UPDATE_METADATA");
+
+ if (!store.messenger) { return; }
+ var curvePublic = p[1];
+ if (!curvePublic) { return; }
+ if (p[2] !== 'channel') { return; }
+ store.messenger.onFriendRemoved(curvePublic, o);
});
proxy.on('change', ['friends_pending'], function () {
// Trigger userlist update when the friendlist has changed
broadcast([], "UPDATE_METADATA");
});
+ proxy.on('remove', ['friends_pending'], function () {
+ broadcast([], "UPDATE_METADATA");
+ });
proxy.on('change', ['settings'], function () {
broadcast([], "UPDATE_METADATA");
});
diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js
new file mode 100644
index 000000000..c0b48f847
--- /dev/null
+++ b/www/common/outer/mailbox-handlers.js
@@ -0,0 +1,52 @@
+define([
+ '/common/common-messaging.js',
+], function (Messaging) {
+
+ var handlers = {};
+
+ handlers['FRIEND_REQUEST'] = function (ctx, data, cb) {
+ if (data.msg.author === data.msg.content.curvePublic &&
+ Messaging.getFriend(ctx.store.proxy, data.msg.author)) {
+ Messaging.acceptFriendRequest(ctx.store, data.msg.content, function (obj) {
+ if (obj && obj.error) { return void cb(); }
+ cb(true);
+ });
+ return;
+ }
+ cb();
+ };
+ handlers['ACCEPT_FRIEND_REQUEST'] = function (ctx, box, data, cb) {
+ // Our friend request was accepted.
+ // Make sure we really sent it
+ if (!ctx.store.proxy.friends_pending[data.msg.author]) { return void cb(); }
+ // And add the friend
+ Messaging.addToFriendList({
+ proxy: ctx.store.proxy,
+ realtime: ctx.store.realtime,
+ pinPads: ctx.pinPads
+ }, data.msg.content, function (err) {
+ if (err) { console.error(err); }
+ delete ctx.store.proxy.friends_pending[data.msg.author];
+ if (ctx.store.messenger) {
+ ctx.store.messenger.onFriendAdded(data.msg.content);
+ }
+ ctx.updateMetadata();
+ });
+ cb();
+ };
+
+ return function (ctx, box, data, cb) {
+ var type = data.msg.type;
+
+ if (handlers[type]) {
+ try {
+ handlers[type](ctx, box, data, cb);
+ } catch (e) {
+ cb();
+ }
+ } else {
+ cb();
+ }
+ };
+});
+
diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js
index 0b4ce7367..f273ca5a5 100644
--- a/www/common/outer/mailbox.js
+++ b/www/common/outer/mailbox.js
@@ -347,11 +347,11 @@ proxy.mailboxes = {
if (BLOCKING_TYPES.indexOf(key) === -1) {
openChannel(ctx, key, m, function () {
updateLastKnownHash(ctx, key);
- console.log(key + ' mailbox is ready');
+ //console.log(key + ' mailbox is ready');
});
} else {
openChannel(ctx, key, m, waitFor(function () {
- console.log(key + ' mailbox is ready');
+ //console.log(key + ' mailbox is ready');
}));
}
});
diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js
index 4aca98e56..bf0cee5cc 100644
--- a/www/common/sframe-common-mailbox.js
+++ b/www/common/sframe-common-mailbox.js
@@ -3,9 +3,10 @@ define([
'/common/common-util.js',
'/common/common-interface.js',
'/common/common-ui-elements.js',
+ '/common/notifications.js',
'/common/hyperscript.js',
'/customize/messages.js'
-], function ($, Util, UI, UIElements, h, Messages) {
+], function ($, Util, UI, UIElements, Notifications, h, Messages) {
var Mailbox = {};
Messages = Messages; // XXX
@@ -87,6 +88,7 @@ define([
var todo = function (f) {
try {
var el = createElement(data);
+ Notifications.add(Common, data, el);
f(data, el);
} catch (e) {
console.error(e);
@@ -103,6 +105,7 @@ define([
onViewedHandlers.forEach(function (f) {
try {
f(data);
+ Notifications.remove(Common, data);
} catch (e) {
console.error(e);
}
@@ -165,7 +168,7 @@ define([
});
execCommand('SUBSCRIBE', null, function () {
- console.log('subscribed');
+ //console.log('subscribed');
});
return mailbox;
diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js
index 7081136c0..38ea38f27 100644
--- a/www/common/sframe-common.js
+++ b/www/common/sframe-common.js
@@ -392,10 +392,17 @@ define([
var friendRequests = {};
funcs.addFriendRequest = function (data) {
var curve = Util.find(data, ['content', 'msg', 'author']);
- console.log(data);
- console.log(curve);
friendRequests[curve] = data;
};
+ funcs.removeFriendRequest = function (hash) {
+ Object.keys(friendRequests).some(function (curve) {
+ var h = Util.find(friendRequests[curve], ['content', 'hash']);
+ if (h === hash) {
+ delete friendRequests[curve];
+ return true;
+ }
+ });
+ };
funcs.getFriendRequests = function () {
return JSON.parse(JSON.stringify(friendRequests));
};
diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js
index d782622e5..d21b3f556 100644
--- a/www/common/toolbar3.js
+++ b/www/common/toolbar3.js
@@ -8,11 +8,10 @@ define([
'/common/common-util.js',
'/common/common-feedback.js',
'/common/hyperscript.js',
- '/common/notifications.js',
'/common/messenger-ui.js',
'/customize/messages.js',
], function ($, Config, ApiConfig, UIElements, UI, Hash, Util, Feedback, h,
-Notifications, MessengerUI, Messages) {
+MessengerUI, Messages) {
var Common;
var Bar = {
@@ -235,9 +234,8 @@ Notifications, MessengerUI, Messages) {
// Editors
var pendingFriends = Common.getPendingFriends(); // Friend requests sent
var friendRequests = Common.getFriendRequests(); // Friend requests received
- console.log(friendRequests);
var friendTo = +new Date() - (2 * 24 * 3600 * 1000);
- friendTo = +new Date(); // XXX
+ //friendTo = +new Date(); // XXX
editUsersNames.forEach(function (data) {
var name = data.name || Messages.anonymous;
var $span = $('', {'class': 'cp-avatar'});
@@ -305,7 +303,6 @@ Notifications, MessengerUI, Messages) {
}
} else if (Common.isLoggedIn() && data.curvePublic && !friends[data.curvePublic]
&& !priv.readOnly) {
- console.log(pendingFriends);
if (pendingFriends[data.curvePublic] && pendingFriends[data.curvePublic] > friendTo) {
$('', {'class': 'cp-toolbar-userlist-friend'}).text(Messages.userlist_pending)
.appendTo($rightCol);
@@ -950,10 +947,11 @@ Notifications, MessengerUI, Messages) {
return $userAdmin;
};
- var createNotifications = function (toolbar) {
- console.log(Common.mailbox);
+ var createNotifications = function (toolbar, config) {
var $notif = toolbar.$top.find('.'+NOTIFICATIONS_CLS).show();
- var div = h('div.cp-notifications-container');
+ var div = h('div.cp-notifications-container', [
+ h('div.cp-notifications-empty', "Nothing new here") // XXX
+ ]);
var pads_options = [div];
var dropdownConfig = {
text: '', // Button initial text
@@ -963,15 +961,35 @@ Notifications, MessengerUI, Messages) {
common: Common
};
var $newPadBlock = UIElements.createDropdown(dropdownConfig);
- $newPadBlock.find('button').attr('title', Messages.mailbox_title); // XXX
- $newPadBlock.find('button').addClass('fa fa-bell-o');
+ var $button = $newPadBlock.find('button');
+ $button.attr('title', Messages.mailbox_title); // XXX
+ $button.addClass('fa fa-bell-o');
+ var $n = $button.find('.cp-dropdown-button-title').hide();
+ var $empty = $(div).find('.cp-notifications-empty');
+
+ var refresh = function () {
+ updateUserList(toolbar, config);
+ var n = $(div).find('.cp-notification').length;
+ $button.removeClass('fa-bell-o').removeClass('fa-bell');
+ if (n === 0) {
+ $empty.show();
+ $n.hide();
+ return void $button.addClass('fa-bell-o');
+ }
+ $empty.hide();
+ $n.text(n).show();
+ $button.addClass('fa-bell');
+ };
Common.mailbox.subscribe({
onMessage: function (data, el) {
if (el) {
- Notifications(Common, data, el);
div.appendChild(el);
}
+ refresh();
+ },
+ onViewed: function (data) {
+ refresh();
}
});