Merge branch 'animal-guests' into staging

pull/1/head
ansuz 4 years ago
commit 0ca482ec68

@ -4,7 +4,11 @@
@width: 30px @width: 30px
) { ) {
@avatar-width: @width; @avatar-width: @width;
@avatar-font-size: @width / 1.2; @avatar-font-size: @width / 1.8;
// scale animal avatar to be somewhat larger, because:
// 1. emojis are wider than most latin characters
// 2. they should occupy the width of two average characters
@avatar-font-size-animal: @avatar-font-size * (6/5);
} }
.avatar_main(@width: 30px) { .avatar_main(@width: 30px) {
--LessLoader_require: LessLoader_currentFile(); --LessLoader_require: LessLoader_currentFile();
@ -40,7 +44,9 @@
color: @cp_avatar-fg; color: @cp_avatar-fg;
font-size: @avatar-font-size; font-size: @avatar-font-size;
font-size: var(--avatar-font-size); font-size: var(--avatar-font-size);
text-transform: capitalize; .animal {
font-size: @avatar-font-size-animal;
}
} }
media-tag { media-tag {
min-height: @avatar-width; min-height: @avatar-width;

@ -855,10 +855,15 @@
span { span {
text-align: center; text-align: center;
width: 100%; width: 100%;
font-size: 48px; .avatar_vars(72px);
font-size: @avatar-font-size;
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
.animal {
font-size: @avatar-font-size-animal;
}
} }
&.cp-avatar { &.cp-avatar {
.avatar_main(64px); .avatar_main(64px);

@ -3,7 +3,9 @@ define([
'/common/sframe-common-codemirror.js', '/common/sframe-common-codemirror.js',
'/customize/messages.js', '/customize/messages.js',
'/bower_components/chainpad/chainpad.dist.js', '/bower_components/chainpad/chainpad.dist.js',
], function (Util, SFCodeMirror, Messages, ChainPad) { '/common/inner/common-mediatag.js',
'/common/common-interface.js',
], function (Util, SFCodeMirror, Messages, ChainPad, MT, UI) {
var Markers = {}; var Markers = {};
/* TODO Known Issues /* TODO Known Issues
@ -38,7 +40,17 @@ define([
}); });
} }
uid = Number(uid); uid = Number(uid);
var name = Util.fixHTML(author.name || Messages.anonymous); var name = Util.fixHTML(UI.getDisplayName(author.name));
var animal;
if ((!name || name === Messages.anonymous) && typeof(author.uid) === 'string') {
animal = MT.getPseudorandomAnimal(author.uid);
if (animal) {
name = animal + ' ' + Messages.anonymous;
} else {
name = Messages.anonymous;
}
}
var col = Util.hexToRGB(author.color); var col = Util.hexToRGB(author.color);
var rgba = 'rgba('+col[0]+','+col[1]+','+col[2]+','+Env.opacity+');'; var rgba = 'rgba('+col[0]+','+col[1]+','+col[2]+','+Env.opacity+');';
return Env.editor.markText(from, to, { return Env.editor.markText(from, to, {
@ -520,7 +532,8 @@ define([
Env.authormarks.authors[Env.myAuthorId] = { Env.authormarks.authors[Env.myAuthorId] = {
name: userData.name, name: userData.name,
curvePublic: userData.curvePublic, curvePublic: userData.curvePublic,
color: userData.color color: userData.color,
uid: userData.uid,
}; };
if (!old || (old.name === userData.name && old.color === userData.color)) { return; } if (!old || (old.name === userData.name && old.color === userData.color)) { return; }
return true; return true;

@ -208,5 +208,7 @@ define(function() {
// the driveless mode by changing the following value to "false" // the driveless mode by changing the following value to "false"
AppConfig.allowDrivelessMode = true; AppConfig.allowDrivelessMode = true;
AppConfig.emojiAvatars = '🙈 🦀 🐞 🦋 🐬 🐋 🐢 🦉 🦆 🐧 🦡 🦘 🦨 🦦 🦥 🐼 🐻 🦝 🦓 🐄 🐷 🐐 🦙 🦒 🐘 🦏 🐁 🐹 🐰 🦫 🦔 🐨 🐱 🐺 👺 👹 👽 👾 🤖'.split(/\s+/);
return AppConfig; return AppConfig;
}); });

@ -41,6 +41,10 @@ define([
return e; return e;
}; };
UI.getDisplayName = function (name) {
return (typeof(name) === 'string'? name: "").trim() || Messages.anonymous;
};
// FIXME almost everywhere this is used would also be // FIXME almost everywhere this is used would also be
// a good candidate for sframe-common's getMediatagFromHref // a good candidate for sframe-common's getMediatagFromHref
UI.mediaTag = function (src, key) { UI.mediaTag = function (src, key) {

@ -17,7 +17,8 @@ define([
edPublic: proxy.edPublic, edPublic: proxy.edPublic,
curvePublic: proxy.curvePublic, curvePublic: proxy.curvePublic,
notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']), notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']),
avatar: proxy.profile && proxy.profile.avatar avatar: proxy.profile && proxy.profile.avatar,
uid: proxy.uid, // XXX test without this and see if it breaks things
}; };
if (hash === false) { delete data.channel; } if (hash === false) { delete data.channel; }
return data; return data;

@ -156,9 +156,11 @@ define([
var icons = Object.keys(users).map(function (key, i) { var icons = Object.keys(users).map(function (key, i) {
var data = users[key]; var data = users[key];
var name = data.displayName || data.name || Messages.anonymous; var name = UI.getDisplayName(data.displayName || data.name);
var avatar = h('span.cp-usergrid-avatar.cp-avatar'); var avatar = h('span.cp-usergrid-avatar.cp-avatar', {
common.displayAvatar($(avatar), data.avatar, name); 'aria-hidden': true, // XXX aria
});
common.displayAvatar($(avatar), data.avatar, name, Util.noop, data.uid);
var removeBtn, el; var removeBtn, el;
if (config.remove) { if (config.remove) {
removeBtn = h('span.fa.fa-times'); removeBtn = h('span.fa.fa-times');
@ -1989,13 +1991,16 @@ define([
var $displayName = $userAdmin.find('.'+displayNameCls); var $displayName = $userAdmin.find('.'+displayNameCls);
var $avatar = $userAdmin.find('> button .cp-dropdown-button-title'); var $avatar = $userAdmin.find('> button .cp-dropdown-button-title'); // XXX alt="User menu"
var loadingAvatar; var loadingAvatar;
var to; var to;
var oldUrl = ''; var oldUrl = '';
var oldUid;
var oldName;
var updateButton = function () { var updateButton = function () {
var myData = metadataMgr.getUserData(); var myData = metadataMgr.getUserData();
var privateData = metadataMgr.getPrivateData(); var privateData = metadataMgr.getPrivateData();
var uid = myData.uid;
if (!priv.plan && privateData.plan) { if (!priv.plan && privateData.plan) {
config.$initBlock.empty(); config.$initBlock.empty();
metadataMgr.off('change', updateButton); metadataMgr.off('change', updateButton);
@ -2010,18 +2015,21 @@ define([
return; return;
} }
loadingAvatar = true; loadingAvatar = true;
var newName = myData.name; var newName = UI.getDisplayName(myData.name);
var url = myData.avatar; var url = myData.avatar;
$displayName.text(newName || Messages.anonymous); $displayName.text(newName);
if (accountName && oldUrl !== url) { if ((accountName && oldUrl !== url) || !accountName && uid !== oldUid || oldName !== newName) {
$avatar.html(''); $avatar.html('');
Common.displayAvatar($avatar, url, Common.displayAvatar($avatar, url, newName, function ($img) {
newName || Messages.anonymous, function ($img) {
oldUrl = url; oldUrl = url;
oldUid = uid;
oldName = newName;
$userAdmin.find('> button').removeClass('cp-avatar'); $userAdmin.find('> button').removeClass('cp-avatar');
if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); } if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); }
loadingAvatar = false; loadingAvatar = false;
});
// XXX alt="User menu"
}, uid);
return; return;
} }
loadingAvatar = false; loadingAvatar = false;
@ -2303,6 +2311,7 @@ define([
var teams = Object.keys(privateData.teams).map(function (id) { var teams = Object.keys(privateData.teams).map(function (id) {
var data = privateData.teams[id]; var data = privateData.teams[id];
var avatar = h('span.cp-creation-team-avatar.cp-avatar'); var avatar = h('span.cp-creation-team-avatar.cp-avatar');
// We assume that teams always have a non-empty name, so we don't need a UID
common.displayAvatar($(avatar), data.avatar, data.name); common.displayAvatar($(avatar), data.avatar, data.name);
return h('div.cp-creation-team', { return h('div.cp-creation-team', {
'data-id': id, 'data-id': id,
@ -3106,7 +3115,7 @@ define([
var sframeChan = common.getSframeChannel(); var sframeChan = common.getSframeChannel();
var msg = data.content.msg; var msg = data.content.msg;
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; var name = Util.fixHTML(UI.getDisplayName(msg.content.user.displayName));
var title = Util.fixHTML(msg.content.title); var title = Util.fixHTML(msg.content.title);
var text = Messages._getKey('owner_add', [name, title]); var text = Messages._getKey('owner_add', [name, title]);
@ -3238,7 +3247,7 @@ define([
var sframeChan = common.getSframeChannel(); var sframeChan = common.getSframeChannel();
var msg = data.content.msg; var msg = data.content.msg;
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; var name = Util.fixHTML(UI.getDisplayName(msg.content.user.displayName));
var title = Util.fixHTML(msg.content.title); var title = Util.fixHTML(msg.content.title);
var text = Messages._getKey('owner_team_add', [name, title]); var text = Messages._getKey('owner_team_add', [name, title]);
@ -3353,13 +3362,15 @@ define([
var verified = h('p'); var verified = h('p');
var $verified = $(verified); var $verified = $(verified);
name = UI.getDisplayName(name);
if (priv.friends && priv.friends[curve]) { if (priv.friends && priv.friends[curve]) {
$verified.addClass('cp-notifications-requestedit-verified'); $verified.addClass('cp-notifications-requestedit-verified');
var f = priv.friends[curve]; var f = priv.friends[curve];
$verified.append(h('span.fa.fa-certificate')); $verified.append(h('span.fa.fa-certificate'));
var $avatar = $(h('span.cp-avatar')).appendTo($verified); var $avatar = $(h('span.cp-avatar')).appendTo($verified);
$verified.append(h('p', Messages._getKey('isContact', [f.displayName]))); name = UI.getDisplayName(f.displayName);
common.displayAvatar($avatar, f.avatar, f.displayName); $verified.append(h('p', Messages._getKey('isContact', [name])));
common.displayAvatar($avatar, f.avatar, name, Util.noop, f.uid);
} else { } else {
$verified.append(Messages._getKey('isNotContact', [name])); $verified.append(Messages._getKey('isNotContact', [name]));
} }
@ -3369,7 +3380,7 @@ define([
UIElements.displayInviteTeamModal = function (common, data) { UIElements.displayInviteTeamModal = function (common, data) {
var msg = data.content.msg; var msg = data.content.msg;
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; var name = Util.fixHTML(UI.getDisplayName(msg.content.user.displayName));
var teamName = Util.fixHTML(Util.find(msg, ['content', 'team', 'metadata', 'name']) || ''); var teamName = Util.fixHTML(Util.find(msg, ['content', 'team', 'metadata', 'name']) || '');
var verified = UIElements.getVerifiedFriend(common, msg.author, name); var verified = UIElements.getVerifiedFriend(common, msg.author, name);
@ -3453,7 +3464,8 @@ define([
name: f.displayName, name: f.displayName,
curvePublic: f.curvePublic, curvePublic: f.curvePublic,
profile: f.profile, profile: f.profile,
notifications: f.notifications notifications: f.notifications,
uid: f.uid,
}; };
}); });
}; };
@ -3552,7 +3564,7 @@ define([
}; };
// Set the value to receive from the autocomplete // Set the value to receive from the autocomplete
var toInsert = function (data, key) { var toInsert = function (data, key) {
var name = data.name.replace(/[^a-zA-Z0-9]+/g, "-"); var name = UI.getDisplayName(data.name.replace(/[^a-zA-Z0-9]+/g, "-"));
return "[@"+name+"|"+key+"]"; return "[@"+name+"|"+key+"]";
}; };
@ -3605,18 +3617,20 @@ define([
var avatar = h('span.cp-avatar', { var avatar = h('span.cp-avatar', {
contenteditable: false contenteditable: false
}); });
common.displayAvatar($(avatar), data.avatar, data.name);
var displayName = UI.getDisplayName(data.name);
common.displayAvatar($(avatar), data.avatar, displayName); // XXX
return h('span.cp-mentions', { return h('span.cp-mentions', {
'data-curve': data.curvePublic, 'data-curve': data.curvePublic,
'data-notifications': data.notifications, 'data-notifications': data.notifications,
'data-profile': data.profile, 'data-profile': data.profile,
'data-name': Util.fixHTML(data.name), 'data-name': Util.fixHTML(displayName),
'data-avatar': data.avatar || "", 'data-avatar': data.avatar || "",
}, [ }, [
avatar, avatar,
h('span.cp-mentions-name', { h('span.cp-mentions-name', {
contenteditable: false contenteditable: false
}, data.name) }, displayName)
]); ]);
}; };
} }
@ -3648,7 +3662,7 @@ define([
}).map(function (key) { }).map(function (key) {
var data = sources[key]; var data = sources[key];
return { return {
label: data.name, label: UI.getDisplayName(data.name),
value: key value: key
}; };
}); });
@ -3683,10 +3697,12 @@ define([
var obj = sources[key]; var obj = sources[key];
if (!obj) { return; } if (!obj) { return; }
var avatar = h('span.cp-avatar'); var avatar = h('span.cp-avatar');
common.displayAvatar($(avatar), obj.avatar, obj.name); var displayName = UI.getDisplayName(obj.name);
common.displayAvatar($(avatar), obj.avatar, displayName, Util.noop, obj.uid);
var li = h('li.cp-autocomplete-value', [ var li = h('li.cp-autocomplete-value', [
avatar, avatar,
h('span', obj.name) h('span', displayName),
]); ]);
return $(li).appendTo(ul); return $(li).appendTo(ul);
}; };

@ -171,7 +171,7 @@ define([
if (!Object.keys(_friends).length) { if (!Object.keys(_friends).length) {
var friendText; var friendText;
if (!friendKeys.length) { if (!friendKeys.length) {
console.error(UIElements.noContactsMessage(common)); //console.error(UIElements.noContactsMessage(common));
var findContacts = UIElements.noContactsMessage(common); var findContacts = UIElements.noContactsMessage(common);
friendText = h('span.cp-app-prop-content', friendText = h('span.cp-app-prop-content',
findContacts.content findContacts.content
@ -772,7 +772,8 @@ define([
if (friend.edPublic !== ed || c === 'me') { return; } if (friend.edPublic !== ed || c === 'me') { return; }
_owners[friend.edPublic] = { _owners[friend.edPublic] = {
name: friend.displayName, name: friend.displayName,
avatar: friend.avatar avatar: friend.avatar,
uid: friend.uid,
}; };
return true; return true;
})) { })) {
@ -782,6 +783,11 @@ define([
_owners[ed] = { _owners[ed] = {
avatar: '?', avatar: '?',
name: Messages.owner_unknownUser, name: Messages.owner_unknownUser,
// TODO a possible enhancement is to use data from the context
// ie. if you have opened the access modal from within the pad
// its owner might be present or they might have left some data
// in the pad itself (as is the case of the uid in rich text comments)
// TODO or just implement "Acquaintances"
}; };
strangers++; strangers++;
}); });

@ -6,12 +6,13 @@ define([
'/common/hyperscript.js', '/common/hyperscript.js',
'/common/media-tag.js', '/common/media-tag.js',
'/customize/messages.js', '/customize/messages.js',
'/customize/application_config.js',
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
'/bower_components/croppie/croppie.min.js', '/bower_components/croppie/croppie.min.js',
'/bower_components/file-saver/FileSaver.min.js', '/bower_components/file-saver/FileSaver.min.js',
'css!/bower_components/croppie/croppie.css', 'css!/bower_components/croppie/croppie.css',
], function ($, Util, Hash, UI, h, MediaTag, Messages) { ], function ($, Util, Hash, UI, h, MediaTag, Messages, AppConfig) {
var MT = {}; var MT = {};
var Nacl = window.nacl; var Nacl = window.nacl;
@ -43,9 +44,16 @@ define([
}); });
}; };
var animal_avatars = {};
MT.getCursorAvatar = function (cursor) { MT.getCursorAvatar = function (cursor) {
var uid = cursor.uid;
// TODO it would be nice to have "{0} is editing" instead of just their name
var html = '<span class="cp-cursor-avatar">'; var html = '<span class="cp-cursor-avatar">';
html += (cursor.avatar && avatars[cursor.avatar]) || ''; if (cursor.avatar && avatars[cursor.avatar]) {
html += avatars[cursor.avatar];
} else if (animal_avatars[uid]) {
html += animal_avatars[uid] + ' ';
}
html += Util.fixHTML(cursor.name) + '</span>'; html += Util.fixHTML(cursor.name) + '</span>';
return html; return html;
}; };
@ -79,12 +87,68 @@ define([
}); });
}; };
MT.displayAvatar = function (common, $container, href, name, _cb) { // https://emojipedia.org/nature/
var ANIMALS = AppConfig.emojiAvatars || [];
var getRandomAnimal = function () { // XXX should never actually happen?
if (!ANIMALS.length) { return ''; }
return ANIMALS[Math.floor(Math.random() * ANIMALS.length)];
};
var getPseudorandomAnimal = MT.getPseudorandomAnimal = function (seed) {
if (!ANIMALS.length) { return ''; }
if (typeof(seed) !== 'string') { return getRandomAnimal(); }
seed = seed.replace(/\D/g, '').slice(0, 10); // XXX possible optimization for on-wire uid
seed = parseInt(seed);
if (!seed) { return getRandomAnimal(); }
return ANIMALS[seed % ANIMALS.length] || '';
};
var getPrettyInitials = MT.getPrettyInitials = function (name) {
var parts = name.split(/\s+/);
var text;
if (parts.length > 1) {
text = parts.slice(0, 2).map(Util.getFirstCharacter).join('');
} else {
text = Util.getFirstCharacter(name);
var second = Util.getFirstCharacter(name.replace(text, ''));
if (second && second !== '?') {
text += second;
}
}
return text;
};
MT.displayAvatar = function (common, $container, href, name, _cb, uid) {
var cb = Util.once(Util.mkAsync(_cb || function () {})); var cb = Util.once(Util.mkAsync(_cb || function () {}));
var displayDefault = function () { var displayDefault = function () {
var text = Util.getFirstCharacter(name || Messages.anonymous); var animal_avatar;
var $avatar = $('<span>', {'class': 'cp-avatar-default'}).text(text); if (uid && animal_avatars[uid]) {
animal_avatar = animal_avatars[uid];
}
name = UI.getDisplayName(name);
var text;
if (ANIMALS.length && name === Messages.anonymous && uid) {
if (animal_avatar) {
text = animal_avatar;
} else {
text = animal_avatar = getPseudorandomAnimal(uid);
}
} else {
text = getPrettyInitials(name);
}
var $avatar = $('<span>', {
'class': 'cp-avatar-default' + (animal_avatar? ' animal': ''),
// XXX prevents screenreaders from trying to describe this
alt: '',
'aria-hidden': true,
}).text(text);
$container.append($avatar); $container.append($avatar);
if (uid && animal_avatar) {
animal_avatars[uid] = animal_avatar;
}
if (cb) { cb(); } if (cb) { cb(); }
}; };
if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol
@ -97,6 +161,7 @@ define([
return void cb($el); return void cb($el);
} }
var centerImage = function ($img, $image) { var centerImage = function ($img, $image) {
var img = $image[0]; var img = $image[0];
var w = img.width; var w = img.width;
@ -131,7 +196,7 @@ define([
var $img = $(mt).appendTo($container); var $img = $(mt).appendTo($container);
MT.displayMediatagImage(common, $img, function (err, $image) { MT.displayMediatagImage(common, $img, function (err, $image) {
if (err) { return void console.error(err); } if (err) { return void console.error(err); }
centerImage($img, $image); centerImage($img, $image); // XXX add alt="" (unless the media-tag has an alt attr)
}); });
}); });
} }

@ -73,6 +73,7 @@ var factory = function () {
* @param {object} cfg Object {Plugins, allowed, download, pdf} containing infos about plugins * @param {object} cfg Object {Plugins, allowed, download, pdf} containing infos about plugins
* @param {function} cb Callback function: (err, pluginElement) => {} * @param {function} cb Callback function: (err, pluginElement) => {}
*/ */
// XXX add alt attributes if present in metadata
text: function (metadata, url, content, cfg, cb) { text: function (metadata, url, content, cfg, cb) {
var plainText = document.createElement('div'); var plainText = document.createElement('div');
plainText.className = "plain-text-reader"; plainText.className = "plain-text-reader";

@ -190,9 +190,11 @@ define([
markup.message = function (msg) { markup.message = function (msg) {
if (msg.type !== 'MSG') { return; } if (msg.type !== 'MSG') { return; }
var curvePublic = msg.author; var curvePublic = msg.author;
// FIXME this assignment looks like it has some holes in its logic
// but I'm scared to touch it because it looks like it was hacked to fix some bugs
var name = (typeof msg.name !== "undefined" || !contactsData[msg.author]) ? var name = (typeof msg.name !== "undefined" || !contactsData[msg.author]) ?
(msg.name || Messages.anonymous) : (msg.name || Messages.anonymous) :
contactsData[msg.author].displayName; contactsData[msg.author].displayName || Messages.anonymous;
var d = msg.time ? new Date(msg.time) : undefined; var d = msg.time ? new Date(msg.time) : undefined;
var day = d ? d.toLocaleDateString() : ''; var day = d ? d.toLocaleDateString() : '';
var hour = d ? d.toLocaleTimeString() : ''; var hour = d ? d.toLocaleTimeString() : '';
@ -239,7 +241,7 @@ define([
}); });
var chan = state.channels[id]; var chan = state.channels[id];
var displayName = chan.name; var displayName = UI.getDisplayName(chan.name || chan.displayName);
var fetching = false; var fetching = false;
var $moreHistory = $(moreHistory).click(function () { var $moreHistory = $(moreHistory).click(function () {
@ -364,7 +366,7 @@ define([
avatars[friend.avatar] = $img[0].outerHTML; avatars[friend.avatar] = $img[0].outerHTML;
} }
$(rightCol).insertAfter($avatar); $(rightCol).insertAfter($avatar);
}); }, friend.uid);
} }
var sending = false; var sending = false;
@ -544,7 +546,7 @@ define([
title: Messages.contacts_online title: Messages.contacts_online
}); });
var rightCol = h('span.cp-app-contacts-right-col', [ var rightCol = h('span.cp-app-contacts-right-col', [
h('span.cp-app-contacts-name', [room.name]), h('span.cp-app-contacts-name', [room.isFriendChat? UI.getDisplayName(room.name): room.name]),
h('span.cp-app-contacts-icons', [ h('span.cp-app-contacts-icons', [
room.isFriendChat ? mute : undefined, room.isFriendChat ? mute : undefined,
room.isFriendChat ? unmute : undefined, room.isFriendChat ? unmute : undefined,
@ -609,7 +611,7 @@ define([
avatars[friendData.avatar] = $img[0].outerHTML; avatars[friendData.avatar] = $img[0].outerHTML;
} }
$room.append(rightCol); $room.append(rightCol);
}); }, friendData.uid);
} }
$room.append(status); $room.append(status);
return $room; return $room;
@ -631,9 +633,9 @@ define([
var el_message = markup.message(message); var el_message = markup.message(message);
if (message.type === 'MSG') { if (message.type === 'MSG') {
var name = typeof message.name !== "undefined" ? var name = UI.getDisplayName(typeof message.name !== "undefined" ?
(message.name || Messages.anonymous) : message.name:
contactsData[message.author].displayName; contactsData[message.author].displayName);
common.notify({ common.notify({
title: name, title: name,
msg: message.text, msg: message.text,
@ -826,6 +828,11 @@ define([
} }
}; };
/* The following block is for a disabled feature which allows users to switch
between pad chat (when in the context of a pad) and direct chats with their
contacts.
*/
/*
common.getMetadataMgr().onTitleChange(function () { common.getMetadataMgr().onTitleChange(function () {
var padChat = common.getPadChat(); var padChat = common.getPadChat();
var md = common.getMetadataMgr().getMetadata(); var md = common.getMetadataMgr().getMetadata();
@ -839,11 +846,14 @@ define([
$lAvatar.find('.cp-avatar-default, media-tag').remove(); $lAvatar.find('.cp-avatar-default, media-tag').remove();
var $div = $('<div>'); var $div = $('<div>');
// 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 () { common.displayAvatar($div, null, name, function () {
$mAvatar.html($div.html()); $mAvatar.html($div.html());
$lAvatar.find('.cp-app-contacts-right-col').before($div.html()); $lAvatar.find('.cp-app-contacts-right-col').before($div.html());
}); });
}); });
*/
// TODO room // TODO room
// var onJoinRoom // var onJoinRoom
@ -878,7 +888,7 @@ define([
h('i.fa.fa-bell'), h('i.fa.fa-bell'),
Messages.contacts_unmute || 'unmute' 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 () { $(button).click(function () {
unmuteUser(curve, button); unmuteUser(curve, button);
execCommand('UNMUTE_USER', curve, function (e, data) { execCommand('UNMUTE_USER', curve, function (e, data) {
@ -894,7 +904,7 @@ define([
}); });
return h('div.cp-contacts-muted-user', [ return h('div.cp-contacts-muted-user', [
h('span', avatar), h('span', avatar),
h('span', data.name), h('span', UI.getDisplayName(data.name)),
button button
]); ]);
}); });

@ -187,6 +187,7 @@ define([
data.color = Util.find(proxy, ['settings', 'general', 'cursor', 'color']); data.color = Util.find(proxy, ['settings', 'general', 'cursor', 'color']);
data.name = proxy[Constants.displayNameKey] || ctx.store.noDriveName || Messages.anonymous; data.name = proxy[Constants.displayNameKey] || ctx.store.noDriveName || Messages.anonymous;
data.avatar = Util.find(proxy, ['profile', 'avatar']); data.avatar = Util.find(proxy, ['profile', 'avatar']);
data.uid = Util.find(proxy, ['uid']) || ctx.store.noDriveUid;
c.cursor = data; c.cursor = data;
sendMyCursor(ctx, client); sendMyCursor(ctx, client);
cb(); cb();

@ -249,11 +249,20 @@ define([
if (existing.indexOf(n) !== -1) { n = 0; } if (existing.indexOf(n) !== -1) { n = 0; }
return n; return n;
}; };
funcs.getAuthorId = function(authors, curve) { funcs.getAuthorId = function(authors, curve, tokenId) {
var existing = Object.keys(authors || {}).map(Number); var existing = Object.keys(authors || {}).map(Number);
if (!funcs.isLoggedIn()) { return authorUid(existing); }
var uid; 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) { existing.some(function(id) {
var author = authors[id] || {}; var author = authors[id] || {};
if (author.curvePublic !== curve) { return; } if (author.curvePublic !== curve) { return; }

@ -356,6 +356,8 @@ MessengerUI, Messages, Pages) {
}); });
} }
if (data.profile) { 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.addClass('cp-userlist-clickable');
$span.click(function () { $span.click(function () {
Common.openURL(origin+'/profile/#' + data.profile); Common.openURL(origin+'/profile/#' + data.profile);
@ -363,7 +365,7 @@ MessengerUI, Messages, Pages) {
} }
Common.displayAvatar($span, data.avatar, name, function () { Common.displayAvatar($span, data.avatar, name, function () {
$span.append($rightCol); $span.append($rightCol);
}); }, data.uid);
$span.data('uid', data.uid); $span.data('uid', data.uid);
$editUsersList.append($span); $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 // Notifications
var initNotifications = function (toolbar, config) { var initNotifications = function (toolbar, config) {
// Display notifications when users are joining/leaving the session // Display notifications when users are joining/leaving the session
var oldUserData; var oldUserData;
if (!config.metadataMgr) { return; } if (!config.metadataMgr) { return; }
var metadataMgr = config.metadataMgr; var metadataMgr = config.metadataMgr;
var notify = function(type, name, oldname) { var notify = function(type, name, oldname, uid) {
if (toolbar.isAlone) { return; } if (toolbar.isAlone) { return; }
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user) // type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
if (typeof name === "undefined") { return; } if (typeof name === "undefined") { return; }
name = name || Messages.anonymous;
if (Config.disableUserlistNotifications) { return; } if (Config.disableUserlistNotifications) { return; }
name = getFancyGuestName(name, uid);
oldname = getFancyGuestName(oldname, uid);
switch(type) { switch(type) {
case 1: case 1:
UI.log(Messages._getKey("notifyJoined", [name])); UI.log(Messages._getKey("notifyJoined", [name]));
@ -1275,7 +1290,7 @@ MessengerUI, Messages, Pages) {
delete oldUserData[u]; delete oldUserData[u];
if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; } if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; }
if (userPresent(u, temp, newdata || oldUserData) < 1) { 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 (typeof oldUserData[k] === "undefined") {
// if the same uid is already present in the userdata, don't notify // if the same uid is already present in the userdata, don't notify
if (!userPresent(k, newdata[k], oldUserData)) { 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) { } 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);
} }
} }
} }

@ -159,6 +159,15 @@
margin-right: 5px; margin-right: 5px;
.tools_unselectable(); .tools_unselectable();
cursor: default; 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 { .kanban-item {

@ -97,16 +97,28 @@ define([
// Tippy // Tippy
var html = MT.getCursorAvatar(cursor); 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 = ''; var text = '';
if (cursor.color) { 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', { var avatar = h('span.cp-cursor.cp-tippy-html' + animal, {
style: "background-color: " + (cursor.color || 'red') + ";"+text, style: text,
'data-cptippy-html': true, 'data-cptippy-html': true,
title: html title: html,
}, l); }, l);
if (!noClear) { if (!noClear) {
cursor.clear = function () { cursor.clear = function () {
@ -1295,12 +1307,12 @@ define([
// Add new cursor // Add new cursor
var avatar = getAvatar(cursor); var avatar = getAvatar(cursor);
var $item = $('.kanban-item[data-eid="'+cursor.item+'"]'); var $item = $('.kanban-item[data-eid="'+cursor.item+'"]');
var $board = $('.kanban-board[data-id="'+cursor.board+'"]');
if ($item.length) { if ($item.length) {
remoteCursors[id] = cursor; remoteCursors[id] = cursor;
$item.find('.cp-kanban-cursors').append(avatar); $item.find('.cp-kanban-cursors').append(avatar);
return; return;
} }
var $board = $('.kanban-board[data-id="'+cursor.board+'"]');
if ($board.length) { if ($board.length) {
remoteCursors[id] = cursor; remoteCursors[id] = cursor;
$board.find('header .cp-kanban-cursors').append(avatar); $board.find('header .cp-kanban-cursors').append(avatar);

@ -43,18 +43,21 @@ define([
var canonicalize = function(t) { return t.replace(/\r\n/g, '\n'); }; var canonicalize = function(t) { return t.replace(/\r\n/g, '\n'); };
var getAuthorId = function(Env, curve) { var getAuthorId = function(Env, curve, uid) {
return Env.common.getAuthorId(Env.comments.authors, curve); return Env.common.getAuthorId(Env.comments.authors, curve, uid);
}; };
// Return the author ID and add/update the data for registered users // Return the author ID and add/update user data
// Return the username for unregistered users // associate data with a curvePublic for registered users and the uid otherwise
var updateAuthorData = function(Env, onChange) { var updateAuthorData = function(Env, onChange) {
var userData = Env.metadataMgr.getUserData(); var userData = Env.metadataMgr.getUserData();
var myAuthorId;
if (!Env.common.isLoggedIn()) { 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 data = Env.comments.authors[myAuthorId] = Env.comments.authors[myAuthorId] || {};
var old = Sortify(data); var old = Sortify(data);
data.name = userData.name; data.name = userData.name;
@ -62,6 +65,8 @@ define([
data.profile = userData.profile; data.profile = userData.profile;
data.curvePublic = userData.curvePublic; data.curvePublic = userData.curvePublic;
data.notifications = userData.notifications; data.notifications = userData.notifications;
data.uid = userData.uid;
if (typeof(onChange) === "function" && Sortify(data) !== old) { if (typeof(onChange) === "function" && Sortify(data) !== old) {
onChange(); onChange();
} }
@ -82,6 +87,9 @@ define([
var userData = Env.metadataMgr.getUserData(); var userData = Env.metadataMgr.getUserData();
var privateData = Env.metadataMgr.getPrivateData(); var privateData = Env.metadataMgr.getPrivateData();
var others = {}; 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 // Get all the other registered users with a mailbox
thread.m.forEach(function(obj) { thread.m.forEach(function(obj) {
var u = obj.u; var u = obj.u;
@ -93,7 +101,8 @@ define([
curvePublic: author.curvePublic, curvePublic: author.curvePublic,
comment: obj.m, comment: obj.m,
content: obj.v, content: obj.v,
notifications: author.notifications notifications: author.notifications,
uid: author.uid,
}; };
}); });
// Send the notification // Send the notification
@ -146,7 +155,7 @@ define([
'aria-required': true, 'aria-required': true,
contenteditable: 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', { var cancel = h('button.btn.btn-cancel', {
tabindex: 1 tabindex: 1
@ -224,7 +233,9 @@ define([
if (Env.common.isLoggedIn()) { if (Env.common.isLoggedIn()) {
var authors = {}; 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]); var obj = Util.clone(Env.comments.authors[id]);
authors[obj.curvePublic] = obj; authors[obj.curvePublic] = obj;
}); });
@ -369,7 +380,7 @@ define([
var name = Util.fixHTML(author.name || Messages.anonymous); var name = Util.fixHTML(author.name || Messages.anonymous);
var date = new Date(msg.t); var date = new Date(msg.t);
var avatar = h('span.cp-avatar'); 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) { if (author.profile) {
$(avatar).click(function(e) { $(avatar).click(function(e) {
Env.common.openURL(Hash.hashToHref(author.profile, 'profile')); Env.common.openURL(Hash.hashToHref(author.profile, 'profile'));
@ -393,7 +404,7 @@ define([
} }
cleanMentions($el); cleanMentions($el);
var avatar = h('span.cp-avatar'); var avatar = h('span.cp-avatar');
Env.common.displayAvatar($(avatar), avatarUrl, name); Env.common.displayAvatar($(avatar), avatarUrl, name, Util.noop, author.uid);
$el.append([ $el.append([
avatar, avatar,
h('span.cp-mentions-name', name) h('span.cp-mentions-name', name)

@ -3,7 +3,9 @@ define([
'/common/common-ui-elements.js', '/common/common-ui-elements.js',
'/common/common-interface.js', '/common/common-interface.js',
'/bower_components/chainpad/chainpad.dist.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 = {}; var Cursor = {};
Cursor.isCursor = function (el) { Cursor.isCursor = function (el) {
@ -40,8 +42,17 @@ define([
var cursors = {}; 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) { 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) { var makeCursor = function (id, cursor) {

@ -349,7 +349,7 @@ define([
$('<img>', { $('<img>', {
src: '/customize/images/avatar.png', src: '/customize/images/avatar.png',
title: Messages.profile_avatar, title: Messages.profile_avatar,
alt: 'Avatar' alt: 'Avatar' // XXX translate this "Default profile picture"
}).appendTo($span); }).appendTo($span);
return; return;
} }
@ -391,7 +391,7 @@ define([
}, function () { }, function () {
sframeChan.query("Q_PROFILE_AVATAR_ADD", data.url, function (err, err2) { sframeChan.query("Q_PROFILE_AVATAR_ADD", data.url, function (err, err2) {
if (err || err2) { return void UI.log(err || err2); } if (err || err2) { return void UI.log(err || err2); }
displayAvatar(data.url); displayAvatar(data.url); // XXX add "Profile picture"
}); });
}); });
}; };

@ -693,6 +693,8 @@ define([
redrawRoster(common); redrawRoster(common);
}); });
}; };
var getDisplayName = UI.getDisplayName;
var makeMember = function (common, data, me, roster) { var makeMember = function (common, data, me, roster) {
if (!data.curvePublic) { return; } if (!data.curvePublic) { return; }
@ -701,11 +703,12 @@ define([
return user.role === "OWNER" && user.curvePublic !== me.curvePublic && !user.pendingOwner; return user.role === "OWNER" && user.curvePublic !== me.curvePublic && !user.pendingOwner;
}); });
var displayName = getDisplayName(data.displayName);
// Avatar // Avatar
var avatar = h('span.cp-avatar.cp-team-member-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 // Name
var name = h('span.cp-team-member-name', data.displayName); var name = h('span.cp-team-member-name', displayName);
if (data.pendingOwner) { if (data.pendingOwner) {
$(name).append(h('em', { $(name).append(h('em', {
title: Messages.team_pendingOwnerTitle title: Messages.team_pendingOwnerTitle
@ -789,7 +792,7 @@ define([
title: Messages.team_rosterKick title: Messages.team_rosterKick
}); });
$(remove).click(function () { $(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; } if (!yes) { return; }
APP.module.execCommand('REMOVE_USER', { APP.module.execCommand('REMOVE_USER', {
pending: data.pending, pending: data.pending,
@ -1073,6 +1076,9 @@ define([
metadata: obj metadata: obj
}, function () { }, function () {
$avatar.empty(); $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); common.displayAvatar($avatar, data.url);
}); });
}); });
@ -1191,10 +1197,11 @@ define([
var displayUser = function (common, data) { var displayUser = function (common, data) {
var avatar = h('span.cp-teams-invite-from-avatar.cp-avatar'); 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', [ return h('div.cp-teams-invite-from-author', [
avatar, 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) { nThen(function (waitFor) {
// Get preview content. // Get preview content.
sframeChan.query('Q_ANON_GET_PREVIEW_CONTENT', { seeds: seeds }, waitFor(function (err, json) { 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(); $(errorBlock).text(Messages.team_inviteInvalidLinkError).show();
waitFor.abort(); waitFor.abort();
$div.empty(); $div.empty();
return; return;
} }
// XXX nothing guarantees that author, teamName, or message exist in json
$div.empty(); $div.empty();
$div.append(h('div.cp-teams-invite-from', [ $div.append(h('div.cp-teams-invite-from', [
Messages.team_inviteFrom || 'From:', Messages.team_inviteFrom,
displayUser(common, json.author) displayUser(common, json.author)
])); ]));
$div.append(UI.setHTML(h('p.cp-teams-invite-to'), $div.append(UI.setHTML(h('p.cp-teams-invite-to'),
Messages._getKey('team_inviteFromMsg', Messages._getKey('team_inviteFromMsg',
[Util.fixHTML(json.author.displayName), [Util.fixHTML(getDisplayName(json.author.displayName)),
Util.fixHTML(json.teamName)]))); Util.fixHTML(json.teamName)])));
if (json.message) { if (json.message) {
$div.append(h('div.cp-teams-invite-message', json.message)); $div.append(h('div.cp-teams-invite-message', json.message));
@ -1449,10 +1457,10 @@ define([
// Update the name in the user menu // Update the name in the user menu
var $displayName = $bar.find('.' + Toolbar.constants.username); var $displayName = $bar.find('.' + Toolbar.constants.username);
metadataMgr.onChange(function () { metadataMgr.onChange(function () {
var name = metadataMgr.getUserData().name || Messages.anonymous; var name = getDisplayName(metadataMgr.getUserData().name);
$displayName.text(name); $displayName.text(name);
}); });
$displayName.text(user.name || Messages.anonymous); $displayName.text(getDisplayName(user.name));
// Load the Team module // Load the Team module
var onEvent = function (obj) { var onEvent = function (obj) {

Loading…
Cancel
Save