');
+ // There should always be a title here (defaultTitle if nothing else)
+ // so we don't ever need to supply a uid for an animal avatar
common.displayAvatar($div, null, name, function () {
$mAvatar.html($div.html());
$lAvatar.find('.cp-app-contacts-right-col').before($div.html());
});
});
+*/
// TODO room
// var onJoinRoom
@@ -878,7 +888,7 @@ define([
h('i.fa.fa-bell'),
Messages.contacts_unmute || 'unmute'
]);
- common.displayAvatar($(avatar), data.avatar, data.name);
+ common.displayAvatar($(avatar), data.avatar, data.name, Util.noop, data.uid);
$(button).click(function () {
unmuteUser(curve, button);
execCommand('UNMUTE_USER', curve, function (e, data) {
@@ -894,7 +904,7 @@ define([
});
return h('div.cp-contacts-muted-user', [
h('span', avatar),
- h('span', data.name),
+ h('span', UI.getDisplayName(data.name)),
button
]);
});
diff --git a/www/common/outer/cursor.js b/www/common/outer/cursor.js
index 95b2b34c6..b1a5e7cd0 100644
--- a/www/common/outer/cursor.js
+++ b/www/common/outer/cursor.js
@@ -187,6 +187,7 @@ define([
data.color = Util.find(proxy, ['settings', 'general', 'cursor', 'color']);
data.name = proxy[Constants.displayNameKey] || ctx.store.noDriveName || Messages.anonymous;
data.avatar = Util.find(proxy, ['profile', 'avatar']);
+ data.uid = Util.find(proxy, ['uid']) || ctx.store.noDriveUid;
c.cursor = data;
sendMyCursor(ctx, client);
cb();
diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js
index 206137c86..000d049b3 100644
--- a/www/common/sframe-common.js
+++ b/www/common/sframe-common.js
@@ -249,11 +249,20 @@ define([
if (existing.indexOf(n) !== -1) { n = 0; }
return n;
};
- funcs.getAuthorId = function(authors, curve) {
+ funcs.getAuthorId = function(authors, curve, tokenId) {
var existing = Object.keys(authors || {}).map(Number);
- if (!funcs.isLoggedIn()) { return authorUid(existing); }
-
var uid;
+ var loggedIn = funcs.isLoggedIn();
+ if (!loggedIn && !tokenId) { return authorUid(existing); }
+ if (!loggedIn) {
+ existing.some(function (id) {
+ var author = authors[id];
+ if (!author || author.uid !== tokenId) { return; }
+ uid = Number(id);
+ return true;
+ });
+ return uid || authorUid(existing);
+ }
existing.some(function(id) {
var author = authors[id] || {};
if (author.curvePublic !== curve) { return; }
diff --git a/www/common/toolbar.js b/www/common/toolbar.js
index d103fe410..5b359a323 100644
--- a/www/common/toolbar.js
+++ b/www/common/toolbar.js
@@ -356,6 +356,8 @@ MessengerUI, Messages, Pages) {
});
}
if (data.profile) {
+ // XXX title to visit their profile "Visit {0}'s profile"
+ // Messages.contacts_info3 "Double-click their icon to view their profile",
$span.addClass('cp-userlist-clickable');
$span.click(function () {
Common.openURL(origin+'/profile/#' + data.profile);
@@ -363,7 +365,7 @@ MessengerUI, Messages, Pages) {
}
Common.displayAvatar($span, data.avatar, name, function () {
$span.append($rightCol);
- });
+ }, data.uid);
$span.data('uid', data.uid);
$editUsersList.append($span);
});
@@ -1215,18 +1217,31 @@ MessengerUI, Messages, Pages) {
}
};
+ var getFancyGuestName = function (name, uid) {
+ name = UI.getDisplayName(name);
+ if (name === Messages.anonymous && uid) {
+ var animal = MT.getPseudorandomAnimal(uid);
+ if (animal) {
+ name = animal + ' ' + name;
+ }
+ }
+ return name;
+ };
+
// Notifications
var initNotifications = function (toolbar, config) {
// Display notifications when users are joining/leaving the session
var oldUserData;
if (!config.metadataMgr) { return; }
var metadataMgr = config.metadataMgr;
- var notify = function(type, name, oldname) {
+ var notify = function(type, name, oldname, uid) {
if (toolbar.isAlone) { return; }
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
if (typeof name === "undefined") { return; }
- name = name || Messages.anonymous;
if (Config.disableUserlistNotifications) { return; }
+ name = getFancyGuestName(name, uid);
+ oldname = getFancyGuestName(oldname, uid);
+
switch(type) {
case 1:
UI.log(Messages._getKey("notifyJoined", [name]));
@@ -1275,7 +1290,7 @@ MessengerUI, Messages, Pages) {
delete oldUserData[u];
if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; }
if (userPresent(u, temp, newdata || oldUserData) < 1) {
- notify(-1, temp.name);
+ notify(-1, temp.name, undefined, temp.uid);
}
}
}
@@ -1295,10 +1310,10 @@ MessengerUI, Messages, Pages) {
if (typeof oldUserData[k] === "undefined") {
// if the same uid is already present in the userdata, don't notify
if (!userPresent(k, newdata[k], oldUserData)) {
- notify(1, newdata[k].name);
+ notify(1, newdata[k].name, undefined, newdata[k].uid);
}
} else if (oldUserData[k].name !== newdata[k].name) {
- notify(0, newdata[k].name, oldUserData[k].name);
+ notify(0, newdata[k].name, oldUserData[k].name, newdata[k].uid);
}
}
}
diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less
index 69924ef77..5996940e4 100644
--- a/www/kanban/app-kanban.less
+++ b/www/kanban/app-kanban.less
@@ -159,6 +159,15 @@
margin-right: 5px;
.tools_unselectable();
cursor: default;
+ &.cp-cursor.cp-tippy-html {
+ .avatar_vars(20px);
+ background-color: var(--red);
+ // XXX figure out how to inherit this from avatar.less
+ font-size: @avatar-font-size; //var(11px; // 20px / 1.8 as per avatar.less..
+ &.animal {
+ font-size: @avatar-font-size-animal; //14px; // 20px / 1.8 * (6/5)...
+ }
+ }
}
}
.kanban-item {
diff --git a/www/kanban/inner.js b/www/kanban/inner.js
index 585c7c285..8225ddc86 100644
--- a/www/kanban/inner.js
+++ b/www/kanban/inner.js
@@ -97,16 +97,28 @@ define([
// Tippy
var html = MT.getCursorAvatar(cursor);
- var l = Util.getFirstCharacter(cursor.name || Messages.anonymous);
+ var name = UI.getDisplayName(cursor.name);
+
+ var l; // label?
+ var animal = '';
+ if (cursor.name === Messages.anonymous && typeof(cursor.uid) === 'string') {
+ l = MT.getPseudorandomAnimal(cursor.uid);
+ if (l) {
+ animal = '.animal';
+ }
+ }
+ if (!l) {
+ l = MT.getPrettyInitials(name);
+ }
var text = '';
if (cursor.color) {
- text = 'color:'+getTextColor(cursor.color)+';';
+ text = 'background-color:' + cursor.color + '; color:'+getTextColor(cursor.color)+';';
}
- var avatar = h('span.cp-cursor.cp-tippy-html', {
- style: "background-color: " + (cursor.color || 'red') + ";"+text,
+ var avatar = h('span.cp-cursor.cp-tippy-html' + animal, {
+ style: text,
'data-cptippy-html': true,
- title: html
+ title: html,
}, l);
if (!noClear) {
cursor.clear = function () {
@@ -1295,12 +1307,12 @@ define([
// Add new cursor
var avatar = getAvatar(cursor);
var $item = $('.kanban-item[data-eid="'+cursor.item+'"]');
- var $board = $('.kanban-board[data-id="'+cursor.board+'"]');
if ($item.length) {
remoteCursors[id] = cursor;
$item.find('.cp-kanban-cursors').append(avatar);
return;
}
+ var $board = $('.kanban-board[data-id="'+cursor.board+'"]');
if ($board.length) {
remoteCursors[id] = cursor;
$board.find('header .cp-kanban-cursors').append(avatar);
diff --git a/www/pad/comments.js b/www/pad/comments.js
index 6069aa1d0..6280a72bf 100644
--- a/www/pad/comments.js
+++ b/www/pad/comments.js
@@ -43,18 +43,21 @@ define([
var canonicalize = function(t) { return t.replace(/\r\n/g, '\n'); };
- var getAuthorId = function(Env, curve) {
- return Env.common.getAuthorId(Env.comments.authors, curve);
+ var getAuthorId = function(Env, curve, uid) {
+ return Env.common.getAuthorId(Env.comments.authors, curve, uid);
};
- // Return the author ID and add/update the data for registered users
- // Return the username for unregistered users
+ // Return the author ID and add/update user data
+ // associate data with a curvePublic for registered users and the uid otherwise
var updateAuthorData = function(Env, onChange) {
var userData = Env.metadataMgr.getUserData();
+ var myAuthorId;
if (!Env.common.isLoggedIn()) {
- return userData.name;
+ myAuthorId = getAuthorId(Env, undefined, userData.uid);
+ } else {
+ myAuthorId = getAuthorId(Env, userData.curvePublic);
}
- var myAuthorId = getAuthorId(Env, userData.curvePublic);
+
var data = Env.comments.authors[myAuthorId] = Env.comments.authors[myAuthorId] || {};
var old = Sortify(data);
data.name = userData.name;
@@ -62,6 +65,8 @@ define([
data.profile = userData.profile;
data.curvePublic = userData.curvePublic;
data.notifications = userData.notifications;
+ data.uid = userData.uid;
+
if (typeof(onChange) === "function" && Sortify(data) !== old) {
onChange();
}
@@ -82,6 +87,9 @@ define([
var userData = Env.metadataMgr.getUserData();
var privateData = Env.metadataMgr.getPrivateData();
var others = {};
+
+
+ // XXX mentioned users should be excluded from the list of notified recipients to avoid notifying them twice
// Get all the other registered users with a mailbox
thread.m.forEach(function(obj) {
var u = obj.u;
@@ -93,7 +101,8 @@ define([
curvePublic: author.curvePublic,
comment: obj.m,
content: obj.v,
- notifications: author.notifications
+ notifications: author.notifications,
+ uid: author.uid,
};
});
// Send the notification
@@ -146,7 +155,7 @@ define([
'aria-required': true,
contenteditable: true,
});
- Env.common.displayAvatar($(avatar), userData.avatar, name);
+ Env.common.displayAvatar($(avatar), userData.avatar, name, Util.noop, userData.uid);
var cancel = h('button.btn.btn-cancel', {
tabindex: 1
@@ -224,7 +233,9 @@ define([
if (Env.common.isLoggedIn()) {
var authors = {};
- Object.keys((Env.comments && Env.comments.authors) || Â {}).forEach(function(id) {
+ Object.keys((Env.comments && Env.comments.authors) || Â {})
+ .filter(function (id) { return Util.find(Env, ['commments', 'authors', id, 'curvePublic']); })
+ .forEach(function(id) {
var obj = Util.clone(Env.comments.authors[id]);
authors[obj.curvePublic] = obj;
});
@@ -369,7 +380,7 @@ define([
var name = Util.fixHTML(author.name || Messages.anonymous);
var date = new Date(msg.t);
var avatar = h('span.cp-avatar');
- Env.common.displayAvatar($(avatar), author.avatar, name);
+ Env.common.displayAvatar($(avatar), author.avatar, name, Util.noop, author.uid);
if (author.profile) {
$(avatar).click(function(e) {
Env.common.openURL(Hash.hashToHref(author.profile, 'profile'));
@@ -393,7 +404,7 @@ define([
}
cleanMentions($el);
var avatar = h('span.cp-avatar');
- Env.common.displayAvatar($(avatar), avatarUrl, name);
+ Env.common.displayAvatar($(avatar), avatarUrl, name, Util.noop, author.uid);
$el.append([
avatar,
h('span.cp-mentions-name', name)
diff --git a/www/pad/cursor.js b/www/pad/cursor.js
index 42569838f..ae91c80f1 100644
--- a/www/pad/cursor.js
+++ b/www/pad/cursor.js
@@ -3,7 +3,9 @@ define([
'/common/common-ui-elements.js',
'/common/common-interface.js',
'/bower_components/chainpad/chainpad.dist.js',
-], function ($, UIElements, UI, ChainPad) {
+ '/customize/messages.js',
+ '/common/inner/common-mediatag.js',
+], function ($, UIElements, UI, ChainPad, Messages, MT) {
var Cursor = {};
Cursor.isCursor = function (el) {
@@ -40,8 +42,17 @@ define([
var cursors = {};
+ // XXX despite the name of this function this doesn't actually render as a tippy tooltip
+ // that means that emojis will use the system font that shows up in native tooltips
+ // so this might be of limited value/aesthetic appeal compared to other apps' cursors
var makeTippy = function (cursor) {
- return cursor.name;
+ if (typeof(cursor.uid) === 'string' && (!cursor.name || cursor.name === Messages.anonymous)) {
+ var animal = MT.getPseudorandomAnimal(cursor.uid);
+ if (animal) {
+ return animal + ' ' + Messages.anonymous;
+ }
+ }
+ return cursor.name || Messages.anonymous;
};
var makeCursor = function (id, cursor) {
diff --git a/www/profile/inner.js b/www/profile/inner.js
index 11abd6ae8..c63b72e99 100644
--- a/www/profile/inner.js
+++ b/www/profile/inner.js
@@ -349,7 +349,7 @@ define([
$('
![]()
', {
src: '/customize/images/avatar.png',
title: Messages.profile_avatar,
- alt: 'Avatar'
+ alt: 'Avatar' // XXX translate this "Default profile picture"
}).appendTo($span);
return;
}
@@ -391,7 +391,7 @@ define([
}, function () {
sframeChan.query("Q_PROFILE_AVATAR_ADD", data.url, function (err, err2) {
if (err || err2) { return void UI.log(err || err2); }
- displayAvatar(data.url);
+ displayAvatar(data.url); // XXX add "Profile picture"
});
});
};
diff --git a/www/teams/inner.js b/www/teams/inner.js
index 373a27998..bd7fca5ed 100644
--- a/www/teams/inner.js
+++ b/www/teams/inner.js
@@ -693,6 +693,8 @@ define([
redrawRoster(common);
});
};
+
+ var getDisplayName = UI.getDisplayName;
var makeMember = function (common, data, me, roster) {
if (!data.curvePublic) { return; }
@@ -701,11 +703,12 @@ define([
return user.role === "OWNER" && user.curvePublic !== me.curvePublic && !user.pendingOwner;
});
+ var displayName = getDisplayName(data.displayName);
// Avatar
var avatar = h('span.cp-avatar.cp-team-member-avatar');
- common.displayAvatar($(avatar), data.avatar, data.displayName);
+ common.displayAvatar($(avatar), data.avatar, displayName, Util.noop, data.uid);
// Name
- var name = h('span.cp-team-member-name', data.displayName);
+ var name = h('span.cp-team-member-name', displayName);
if (data.pendingOwner) {
$(name).append(h('em', {
title: Messages.team_pendingOwnerTitle
@@ -789,7 +792,7 @@ define([
title: Messages.team_rosterKick
});
$(remove).click(function () {
- UI.confirm(Messages._getKey('team_kickConfirm', [Util.fixHTML(data.displayName)]), function (yes) {
+ UI.confirm(Messages._getKey('team_kickConfirm', [Util.fixHTML(displayName)]), function (yes) {
if (!yes) { return; }
APP.module.execCommand('REMOVE_USER', {
pending: data.pending,
@@ -1073,6 +1076,9 @@ define([
metadata: obj
}, function () {
$avatar.empty();
+ // the UI is not supposed to allow admins to remove team names
+ // so we expect that it will be there. Failing that the initials
+ // from the default name will be displayed
common.displayAvatar($avatar, data.url);
});
});
@@ -1191,10 +1197,11 @@ define([
var displayUser = function (common, data) {
var avatar = h('span.cp-teams-invite-from-avatar.cp-avatar');
- common.displayAvatar($(avatar), data.avatar, data.displayName);
+ var name = getDisplayName(data.displayName);
+ common.displayAvatar($(avatar), data.avatar, name);
return h('div.cp-teams-invite-from-author', [
avatar,
- h('span.cp-teams-invite-from-name', data.displayName)
+ h('span.cp-teams-invite-from-name', name)
]);
};
@@ -1319,20 +1326,21 @@ define([
nThen(function (waitFor) {
// Get preview content.
sframeChan.query('Q_ANON_GET_PREVIEW_CONTENT', { seeds: seeds }, waitFor(function (err, json) {
- if (json && (json.error || !Object.keys(json).length)) {
+ if (json && (json.error || !Object.keys(json).length)) { // XXX team invite links are triggering this every time for me?
$(errorBlock).text(Messages.team_inviteInvalidLinkError).show();
waitFor.abort();
$div.empty();
return;
}
+ // XXX nothing guarantees that author, teamName, or message exist in json
$div.empty();
$div.append(h('div.cp-teams-invite-from', [
- Messages.team_inviteFrom || 'From:',
+ Messages.team_inviteFrom,
displayUser(common, json.author)
]));
$div.append(UI.setHTML(h('p.cp-teams-invite-to'),
Messages._getKey('team_inviteFromMsg',
- [Util.fixHTML(json.author.displayName),
+ [Util.fixHTML(getDisplayName(json.author.displayName)),
Util.fixHTML(json.teamName)])));
if (json.message) {
$div.append(h('div.cp-teams-invite-message', json.message));
@@ -1449,10 +1457,10 @@ define([
// Update the name in the user menu
var $displayName = $bar.find('.' + Toolbar.constants.username);
metadataMgr.onChange(function () {
- var name = metadataMgr.getUserData().name || Messages.anonymous;
+ var name = getDisplayName(metadataMgr.getUserData().name);
$displayName.text(name);
});
- $displayName.text(user.name || Messages.anonymous);
+ $displayName.text(getDisplayName(user.name));
// Load the Team module
var onEvent = function (obj) {