From 82101bcb9b16ee2a7c187f4eab310bc8789ed358 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 19 Aug 2021 21:16:49 +0530 Subject: [PATCH 01/20] use two characters for the default avatar --- customize.dist/src/less2/include/avatar.less | 2 +- customize.dist/src/less2/include/toolbar.less | 2 +- www/common/inner/common-mediatag.js | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/customize.dist/src/less2/include/avatar.less b/customize.dist/src/less2/include/avatar.less index 725c7748f..02abc4050 100644 --- a/customize.dist/src/less2/include/avatar.less +++ b/customize.dist/src/less2/include/avatar.less @@ -4,7 +4,7 @@ @width: 30px ) { @avatar-width: @width; - @avatar-font-size: @width / 1.2; + @avatar-font-size: @width / 1.8; } .avatar_main(@width: 30px) { --LessLoader_require: LessLoader_currentFile(); diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index b0f9b5e42..28b513095 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -855,7 +855,7 @@ span { text-align: center; width: 100%; - font-size: 48px; + font-size: 40px; display: inline-flex; justify-content: center; align-items: center; diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 1d88e1029..03d85fab0 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -82,7 +82,16 @@ define([ MT.displayAvatar = function (common, $container, href, name, _cb) { var cb = Util.once(Util.mkAsync(_cb || function () {})); var displayDefault = function () { - var text = Util.getFirstCharacter(name || Messages.anonymous); + name = (name || "").trim() || Messages.anonymous; + 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); + text += Util.getFirstCharacter(name.replace(text, '')); + } + var $avatar = $('', {'class': 'cp-avatar-default'}).text(text); $container.append($avatar); if (cb) { cb(); } From b8c847bccef0001553cfc09724f38939dd8cd74c Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 19 Aug 2021 22:25:51 +0530 Subject: [PATCH 02/20] prototype animal avatars for guests that haven't set a custom name --- www/common/inner/common-mediatag.js | 34 ++++++++++++++++++++++++++--- www/common/toolbar.js | 5 +++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 03d85fab0..2dc912e02 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -79,21 +79,48 @@ define([ }); }; - MT.displayAvatar = function (common, $container, href, name, _cb) { + // https://emojipedia.org/nature/ + var ANIMALS = [ '🙈', 'đŸĻ€', '🐞', 'đŸĻ‹', 'đŸŦ', '🐋', 'đŸĸ', 'đŸĻ‰', 'đŸĻ†', '🐧', 'đŸĻĄ', 'đŸĻ˜', 'đŸĻ¨', 'đŸĻĻ', 'đŸĻĨ', 'đŸŧ', 'đŸģ', 'đŸĻ', 'đŸĻ„', '🐄', '🐷', '🐐', 'đŸĻ™', 'đŸĻ’', '🐘', 'đŸĻ', '🐁', '🐹', '🐰', 'đŸĻĢ', 'đŸĻ”', '🐨']; + + var getRandomAnimal = function () { + return ANIMALS[Math.floor(Math.random() * ANIMALS.length)]; + }; + + var getPseudorandomAnimal = function (seed) { + if (typeof(seed) !== 'string') { return getRandomAnimal(); } + seed = seed.replace(/\D/g, '').slice(0, 10); + seed = parseInt(seed); + if (!seed) { return getRandomAnimal(); } + return ANIMALS[seed % ANIMALS.length]; + }; + + MT.displayAvatar = function (common, $container, href, name, _cb, uid) { var cb = Util.once(Util.mkAsync(_cb || function () {})); var displayDefault = function () { + if (avatars[uid]) { + var nodes = $.parseHTML(avatars[uid]); + var $el = $(nodes[0]); + $container.append($el); + return void cb($el); + } + var animal = false; + name = (name || "").trim() || Messages.anonymous; var parts = name.split(/\s+/); var text; - if (parts.length > 1) { + if (name === Messages.anonymous) { + text = getPseudorandomAnimal(uid); + animal = true; + } else if (parts.length > 1) { text = parts.slice(0, 2).map(Util.getFirstCharacter).join(''); } else { text = Util.getFirstCharacter(name); text += Util.getFirstCharacter(name.replace(text, '')); } - var $avatar = $('', {'class': 'cp-avatar-default'}).text(text); + var $avatar = $('', {'class': 'cp-avatar-default' + (animal? ' animal': '')}).text(text); $container.append($avatar); + avatars[uid] = $avatar[0].outerHTML; if (cb) { cb(); } }; if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol @@ -106,6 +133,7 @@ define([ return void cb($el); } + var centerImage = function ($img, $image) { var img = $image[0]; var w = img.width; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index d103fe410..791857049 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -361,9 +361,10 @@ MessengerUI, Messages, Pages) { Common.openURL(origin+'/profile/#' + data.profile); }); } - Common.displayAvatar($span, data.avatar, name, function () { + console.error("AVATAR", $span, data.uid); + Common.displayAvatar($span, data.avatar, name, function () { // XXX pass a little more info so we can display better (pseudo-random) defaults $span.append($rightCol); - }); + }, data.uid); $span.data('uid', data.uid); $editUsersList.append($span); }); From c5e6ca646eb0ab2868f3c2c31602537e6cbfed19 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 20 Aug 2021 15:57:14 +0530 Subject: [PATCH 03/20] adjust animal avatar caching system and adjust size in the toolbar --- customize.dist/src/less2/include/toolbar.less | 3 +++ www/common/inner/common-mediatag.js | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 28b513095..d8029f0d2 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -200,6 +200,9 @@ .avatar_main(30px); .cp-avatar-default, media-tag { margin-right: 5px; + &.animal { + font-size: 20px; + } } &.cp-userlist-clickable { cursor: pointer; diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 2dc912e02..ece9e3024 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -80,7 +80,7 @@ define([ }; // https://emojipedia.org/nature/ - var ANIMALS = [ '🙈', 'đŸĻ€', '🐞', 'đŸĻ‹', 'đŸŦ', '🐋', 'đŸĸ', 'đŸĻ‰', 'đŸĻ†', '🐧', 'đŸĻĄ', 'đŸĻ˜', 'đŸĻ¨', 'đŸĻĻ', 'đŸĻĨ', 'đŸŧ', 'đŸģ', 'đŸĻ', 'đŸĻ„', '🐄', '🐷', '🐐', 'đŸĻ™', 'đŸĻ’', '🐘', 'đŸĻ', '🐁', '🐹', '🐰', 'đŸĻĢ', 'đŸĻ”', '🐨']; + var ANIMALS = '🙈 đŸĻ€ 🐞 đŸĻ‹ đŸŦ 🐋 đŸĸ đŸĻ‰ đŸĻ† 🐧 đŸĻĄ đŸĻ˜ đŸĻ¨ đŸĻĻ đŸĻĨ đŸŧ đŸģ đŸĻ đŸĻ“ 🐄 🐷 🐐 đŸĻ™ đŸĻ’ 🐘 đŸĻ 🐁 🐹 🐰 đŸĻĢ đŸĻ” 🐨 🐱 đŸē đŸ‘ē 👹 đŸ‘Ŋ 👾 🤖'.split(/\s+/); var getRandomAnimal = function () { return ANIMALS[Math.floor(Math.random() * ANIMALS.length)]; @@ -94,14 +94,13 @@ define([ return ANIMALS[seed % ANIMALS.length]; }; + var animal_avatars = {}; MT.displayAvatar = function (common, $container, href, name, _cb, uid) { var cb = Util.once(Util.mkAsync(_cb || function () {})); var displayDefault = function () { - if (avatars[uid]) { - var nodes = $.parseHTML(avatars[uid]); - var $el = $(nodes[0]); - $container.append($el); - return void cb($el); + var animal_avatar; + if (uid && animal_avatars[uid]) { + animal_avatar = animal_avatars[uid] } var animal = false; @@ -109,7 +108,11 @@ define([ var parts = name.split(/\s+/); var text; if (name === Messages.anonymous) { - text = getPseudorandomAnimal(uid); + if (animal_avatar) { + text = animal_avatar; + } else { + text = animal_avatar = getPseudorandomAnimal(uid); + } animal = true; } else if (parts.length > 1) { text = parts.slice(0, 2).map(Util.getFirstCharacter).join(''); @@ -120,7 +123,9 @@ define([ var $avatar = $('', {'class': 'cp-avatar-default' + (animal? ' animal': '')}).text(text); $container.append($avatar); - avatars[uid] = $avatar[0].outerHTML; + if (uid && animal) { + animal_avatars[uid] = animal_avatar; + } if (cb) { cb(); } }; if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol From 46e545a976ef9312f9aa0018aaca7dca614cedf1 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 23 Aug 2021 16:34:51 +0530 Subject: [PATCH 04/20] lint compliance --- www/common/inner/common-mediatag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index ece9e3024..3d4e82caf 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -100,7 +100,7 @@ define([ var displayDefault = function () { var animal_avatar; if (uid && animal_avatars[uid]) { - animal_avatar = animal_avatars[uid] + animal_avatar = animal_avatars[uid]; } var animal = false; From 385cd4e947aaa0494c21502fa7d92460a5b8ab2a Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 12:05:25 +0530 Subject: [PATCH 05/20] handle single-character usernames when deriving initials from usernames and use emoji avatar in user admin button --- www/common/common-ui-elements.js | 7 +++++-- www/common/inner/common-mediatag.js | 23 +++++++++++++++++------ www/common/toolbar.js | 2 +- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8315768f1..a4d84796d 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1993,9 +1993,11 @@ define([ var loadingAvatar; var to; var oldUrl = ''; + var oldUid = undefined; var updateButton = function () { var myData = metadataMgr.getUserData(); var privateData = metadataMgr.getPrivateData(); + var uid = myData.uid; if (!priv.plan && privateData.plan) { config.$initBlock.empty(); metadataMgr.off('change', updateButton); @@ -2013,15 +2015,16 @@ define([ var newName = myData.name; var url = myData.avatar; $displayName.text(newName || Messages.anonymous); - if (accountName && oldUrl !== url) { + if ((accountName && oldUrl !== url) || !accountName && uid !== oldUid) { $avatar.html(''); Common.displayAvatar($avatar, url, newName || Messages.anonymous, function ($img) { oldUrl = url; + oldUid = uid; $userAdmin.find('> button').removeClass('cp-avatar'); if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); } loadingAvatar = false; - }); + }, uid); return; } loadingAvatar = false; diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 3d4e82caf..bceb314b8 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -94,6 +94,21 @@ define([ return ANIMALS[seed % ANIMALS.length]; }; + var 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; + }; + var animal_avatars = {}; MT.displayAvatar = function (common, $container, href, name, _cb, uid) { var cb = Util.once(Util.mkAsync(_cb || function () {})); @@ -105,20 +120,16 @@ define([ var animal = false; name = (name || "").trim() || Messages.anonymous; - var parts = name.split(/\s+/); var text; - if (name === Messages.anonymous) { + if (name === Messages.anonymous && uid) { if (animal_avatar) { text = animal_avatar; } else { text = animal_avatar = getPseudorandomAnimal(uid); } animal = true; - } else if (parts.length > 1) { - text = parts.slice(0, 2).map(Util.getFirstCharacter).join(''); } else { - text = Util.getFirstCharacter(name); - text += Util.getFirstCharacter(name.replace(text, '')); + text = getPrettyInitials(name); } var $avatar = $('', {'class': 'cp-avatar-default' + (animal? ' animal': '')}).text(text); diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 791857049..7493d9996 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -362,7 +362,7 @@ MessengerUI, Messages, Pages) { }); } console.error("AVATAR", $span, data.uid); - Common.displayAvatar($span, data.avatar, name, function () { // XXX pass a little more info so we can display better (pseudo-random) defaults + Common.displayAvatar($span, data.avatar, name, function () { $span.append($rightCol); }, data.uid); $span.data('uid', data.uid); From 8d579c037645ff3b33bdb4c059b8ba1a90f7ba66 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 12:57:24 +0530 Subject: [PATCH 06/20] Add avatars to rich text comments and mentions --- www/common/common-ui-elements.js | 21 ++++++++++++-------- www/common/sframe-common.js | 13 ++++++++++--- www/pad/comments.js | 33 +++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index a4d84796d..943050e62 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3456,7 +3456,8 @@ define([ name: f.displayName, curvePublic: f.curvePublic, profile: f.profile, - notifications: f.notifications + notifications: f.notifications, + uid: f.uid, }; }); }; @@ -3555,7 +3556,7 @@ define([ }; // Set the value to receive from the autocomplete var toInsert = function (data, key) { - var name = data.name.replace(/[^a-zA-Z0-9]+/g, "-"); + var name = (data.name.replace(/[^a-zA-Z0-9]+/g, "-") || "").trim() || Messages.anonymous; // XXX return "[@"+name+"|"+key+"]"; }; @@ -3608,18 +3609,20 @@ define([ var avatar = h('span.cp-avatar', { contenteditable: false }); - common.displayAvatar($(avatar), data.avatar, data.name); + + var displayName = (data.name || "").trim() || Messages.anonymous; + common.displayAvatar($(avatar), data.avatar, displayName); // XXX return h('span.cp-mentions', { 'data-curve': data.curvePublic, 'data-notifications': data.notifications, 'data-profile': data.profile, - 'data-name': Util.fixHTML(data.name), + 'data-name': Util.fixHTML(displayName), 'data-avatar': data.avatar || "", }, [ avatar, h('span.cp-mentions-name', { contenteditable: false - }, data.name) + }, displayName) ]); }; } @@ -3651,7 +3654,7 @@ define([ }).map(function (key) { var data = sources[key]; return { - label: data.name, + label: (data.name || "").trim() || Messages.anonymous, value: key }; }); @@ -3686,10 +3689,12 @@ define([ var obj = sources[key]; if (!obj) { return; } var avatar = h('span.cp-avatar'); - common.displayAvatar($(avatar), obj.avatar, obj.name); + var displayName = (obj.name || "").trim() || Messages.anonymous; + + common.displayAvatar($(avatar), obj.avatar, displayName, Util.noop, obj.uid); // XXX var li = h('li.cp-autocomplete-value', [ avatar, - h('span', obj.name) + h('span', displayName), ]); return $(li).appendTo(ul); }; diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 206137c86..01c48b540 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -249,11 +249,18 @@ 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; + if (!funcs.isLoggedIn()) { + existing.some(function (id) { + var author = authors[id] || {}; + if (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/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) From c630abb3c56abd451c2968800d49e9245557533a Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 12:59:37 +0530 Subject: [PATCH 07/20] refactor animal avatar font-size to automatically scale with parents --- customize.dist/src/less2/include/avatar.less | 8 +++++++- customize.dist/src/less2/include/toolbar.less | 3 --- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/customize.dist/src/less2/include/avatar.less b/customize.dist/src/less2/include/avatar.less index 02abc4050..079ceb60d 100644 --- a/customize.dist/src/less2/include/avatar.less +++ b/customize.dist/src/less2/include/avatar.less @@ -40,7 +40,13 @@ color: @cp_avatar-fg; font-size: @avatar-font-size; font-size: var(--avatar-font-size); - text-transform: capitalize; + .animal { + font-size: 20px; + // 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 + font-size: calc(var(--avatar-width) * (6/5)); + } } media-tag { min-height: @avatar-width; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index d8029f0d2..28b513095 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -200,9 +200,6 @@ .avatar_main(30px); .cp-avatar-default, media-tag { margin-right: 5px; - &.animal { - font-size: 20px; - } } &.cp-userlist-clickable { cursor: pointer; From c4fcc9f732ad3eb2b95c6291dc128d1305707c58 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 13:03:27 +0530 Subject: [PATCH 08/20] WIP comments and non-functional changes --- www/common/common-ui-elements.js | 14 +++++++++----- www/common/inner/common-mediatag.js | 9 +++++++-- www/common/media-tag.js | 1 + www/common/toolbar.js | 3 ++- www/kanban/inner.js | 20 ++++++++++---------- www/profile/inner.js | 4 ++-- www/slide/inner.js | 2 +- 7 files changed, 32 insertions(+), 21 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 943050e62..6bb409222 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -157,8 +157,10 @@ define([ var icons = Object.keys(users).map(function (key, i) { var data = users[key]; var name = data.displayName || data.name || Messages.anonymous; - var avatar = h('span.cp-usergrid-avatar.cp-avatar'); - common.displayAvatar($(avatar), data.avatar, name); + var avatar = h('span.cp-usergrid-avatar.cp-avatar', { + 'aria-hidden': true, // XXX aria + }); + common.displayAvatar($(avatar), data.avatar, name); // XXX var removeBtn, el; if (config.remove) { removeBtn = h('span.fa.fa-times'); @@ -1989,11 +1991,11 @@ define([ 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 to; var oldUrl = ''; - var oldUid = undefined; + var oldUid; var updateButton = function () { var myData = metadataMgr.getUserData(); var privateData = metadataMgr.getPrivateData(); @@ -2024,6 +2026,8 @@ define([ $userAdmin.find('> button').removeClass('cp-avatar'); if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); } loadingAvatar = false; + + // XXX alt="User menu" }, uid); return; } @@ -2306,7 +2310,7 @@ define([ var teams = Object.keys(privateData.teams).map(function (id) { var data = privateData.teams[id]; var avatar = h('span.cp-creation-team-avatar.cp-avatar'); - common.displayAvatar($(avatar), data.avatar, data.name); + common.displayAvatar($(avatar), data.avatar, data.name); // XXX return h('div.cp-creation-team', { 'data-id': id, title: data.name, diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index bceb314b8..54b20784a 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -132,7 +132,12 @@ define([ text = getPrettyInitials(name); } - var $avatar = $('', {'class': 'cp-avatar-default' + (animal? ' animal': '')}).text(text); + var $avatar = $('', { + 'class': 'cp-avatar-default' + (animal? ' animal': ''), + // XXX prevents screenreaders from trying to describe this + alt: '', + 'aria-hidden': true, + }).text(text); $container.append($avatar); if (uid && animal) { animal_avatars[uid] = animal_avatar; @@ -184,7 +189,7 @@ define([ var $img = $(mt).appendTo($container); MT.displayMediatagImage(common, $img, function (err, $image) { if (err) { return void console.error(err); } - centerImage($img, $image); + centerImage($img, $image); // XXX add alt="" (unless the media-tag has an alt attr) }); }); } diff --git a/www/common/media-tag.js b/www/common/media-tag.js index 15b038724..d1a5ebcda 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -73,6 +73,7 @@ var factory = function () { * @param {object} cfg Object {Plugins, allowed, download, pdf} containing infos about plugins * @param {function} cb Callback function: (err, pluginElement) => {} */ + // XXX add alt attributes if present in metadata text: function (metadata, url, content, cfg, cb) { var plainText = document.createElement('div'); plainText.className = "plain-text-reader"; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 7493d9996..da8b1dad0 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -356,12 +356,13 @@ 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); }); } - console.error("AVATAR", $span, data.uid); Common.displayAvatar($span, data.avatar, name, function () { $span.append($rightCol); }, data.uid); diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 38e933cf1..42b1e39fa 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -59,7 +59,7 @@ define([ verbose = function () {}; // comment out to enable verbose logging var onRedraw = Util.mkEvent(); var onCursorUpdate = Util.mkEvent(); - var remoteCursors = {}; + var remoteCursors = {}; // XXX var setValueAndCursor = function (input, val, _cursor) { if (!input) { return; } @@ -95,7 +95,7 @@ define([ var getAvatar = function (cursor, noClear) { // Tippy - var html = MT.getCursorAvatar(cursor); + var html = MT.getCursorAvatar(cursor); // XXX var l = Util.getFirstCharacter(cursor.name || Messages.anonymous); @@ -103,10 +103,10 @@ define([ if (cursor.color) { text = 'color:'+getTextColor(cursor.color)+';'; } - var avatar = h('span.cp-cursor.cp-tippy-html', { + var avatar = h('span.cp-cursor.cp-tippy-html', { // XXX style: "background-color: " + (cursor.color || 'red') + ";"+text, 'data-cptippy-html': true, - title: html + title: html, // XXX "{0} is editing" }, l); if (!noClear) { cursor.clear = function () { @@ -852,7 +852,7 @@ define([ getAvatar: getAvatar, openLink: openLink, getTags: getExistingTags, - cursors: remoteCursors, + cursors: remoteCursors, // XXX boards: boards, _boards: Util.clone(boards), }); @@ -1101,7 +1101,7 @@ define([ $container.find('.kanban-edit-item').remove(); }); - var getCursor = function () { + var getCursor = function () { // XXX if (!kanban || !kanban.inEditMode) { return; } try { var id = kanban.inEditMode; @@ -1204,7 +1204,7 @@ define([ var remoteContent = newContent.content; if (Sortify(currentContent) !== Sortify(remoteContent)) { - var cursor = getCursor(); + var cursor = getCursor(); // XXX verbose("Content is different.. Applying content"); kanban.options.boards = remoteContent; updateBoards(framework, kanban, remoteContent); @@ -1261,11 +1261,11 @@ define([ }); var myCursor = {}; - onCursorUpdate.reg(function (data) { + onCursorUpdate.reg(function (data) { // XXX myCursor = data; framework.updateCursor(); }); - framework.onCursorUpdate(function (data) { + framework.onCursorUpdate(function (data) { // XXX if (!data) { return; } if (data.reset) { Object.keys(remoteCursors).forEach(function (id) { @@ -1293,7 +1293,7 @@ define([ if (!cursor.item && !cursor.board) { return; } // Add new cursor - var avatar = getAvatar(cursor); + var avatar = getAvatar(cursor); // XXX var $item = $('.kanban-item[data-eid="'+cursor.item+'"]'); var $board = $('.kanban-board[data-id="'+cursor.board+'"]'); if ($item.length) { 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/slide/inner.js b/www/slide/inner.js index 9c9b9c70b..143165176 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -511,7 +511,7 @@ define([ framework.updateCursor(); }, 500); // 500ms to make sure it is sent after chainpad sync }; - framework.onCursorUpdate(CodeMirror.setRemoteCursor); + framework.onCursorUpdate(CodeMirror.setRemoteCursor); // XXX framework.setCursorGetter(CodeMirror.getCursor); editor.on('cursorActivity', updateCursor); From 4b0cebb0fd46f0d0339320160407b2859caa42ff Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 13:19:51 +0530 Subject: [PATCH 09/20] animal emojis in the team roster and fall back to default username in teams when members are unnamed in various places where it was not handled --- www/teams/inner.js | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/www/teams/inner.js b/www/teams/inner.js index 373a27998..d1e383e44 100644 --- a/www/teams/inner.js +++ b/www/teams/inner.js @@ -693,6 +693,10 @@ define([ redrawRoster(common); }); }; + + var getDisplayName = function (name) { + return (typeof(name) === 'string'? name: "").trim() || Messages.anonymous; + }; var makeMember = function (common, data, me, roster) { if (!data.curvePublic) { return; } @@ -701,11 +705,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 +794,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 +1078,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 +1199,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 +1328,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 +1459,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) { From 95869b84c901ce48f69d1ad0fa49e9a6cfe31915 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 13:38:05 +0530 Subject: [PATCH 10/20] emoji avatars in the contacts app and handling of empty display names --- www/common/common-interface.js | 4 ++++ www/common/common-messaging.js | 3 ++- www/common/messenger-ui.js | 30 ++++++++++++++++++++---------- www/teams/inner.js | 4 +--- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 71a1ed8af..5c2431efd 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -41,6 +41,10 @@ define([ return e; }; + UI.getDisplayName = function (name) { + return (typeof(name) === 'string'? name: "").trim() || Messages.anonymous; + }; + // FIXME almost everywhere this is used would also be // a good candidate for sframe-common's getMediatagFromHref UI.mediaTag = function (src, key) { diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index 65f05961e..4a3eb2a91 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -17,7 +17,8 @@ define([ edPublic: proxy.edPublic, curvePublic: proxy.curvePublic, notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']), - avatar: proxy.profile && proxy.profile.avatar + avatar: proxy.profile && proxy.profile.avatar, + uid: proxy.uid, }; if (hash === false) { delete data.channel; } return data; diff --git a/www/common/messenger-ui.js b/www/common/messenger-ui.js index 76a756a11..494001624 100644 --- a/www/common/messenger-ui.js +++ b/www/common/messenger-ui.js @@ -190,9 +190,11 @@ define([ markup.message = function (msg) { if (msg.type !== 'MSG') { return; } 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]) ? (msg.name || Messages.anonymous) : - contactsData[msg.author].displayName; + contactsData[msg.author].displayName || Messages.anonymous; var d = msg.time ? new Date(msg.time) : undefined; var day = d ? d.toLocaleDateString() : ''; var hour = d ? d.toLocaleTimeString() : ''; @@ -239,7 +241,7 @@ define([ }); var chan = state.channels[id]; - var displayName = chan.name; + var displayName = UI.getDisplayName(chan.name || chan.displayName); var fetching = false; var $moreHistory = $(moreHistory).click(function () { @@ -364,7 +366,7 @@ define([ avatars[friend.avatar] = $img[0].outerHTML; } $(rightCol).insertAfter($avatar); - }); + }, friend.uid); } var sending = false; @@ -544,7 +546,7 @@ define([ title: Messages.contacts_online }); 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', [ room.isFriendChat ? mute : undefined, room.isFriendChat ? unmute : undefined, @@ -609,7 +611,7 @@ define([ avatars[friendData.avatar] = $img[0].outerHTML; } $room.append(rightCol); - }); + }, friendData.uid); } $room.append(status); return $room; @@ -631,9 +633,9 @@ define([ var el_message = markup.message(message); if (message.type === 'MSG') { - var name = typeof message.name !== "undefined" ? - (message.name || Messages.anonymous) : - contactsData[message.author].displayName; + var name = UI.getDisplayName(typeof message.name !== "undefined" ? + message.name: + contactsData[message.author].displayName); common.notify({ title: name, 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 () { var padChat = common.getPadChat(); var md = common.getMetadataMgr().getMetadata(); @@ -839,11 +846,14 @@ define([ $lAvatar.find('.cp-avatar-default, media-tag').remove(); var $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 () { $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/teams/inner.js b/www/teams/inner.js index d1e383e44..bd7fca5ed 100644 --- a/www/teams/inner.js +++ b/www/teams/inner.js @@ -694,9 +694,7 @@ define([ }); }; - var getDisplayName = function (name) { - return (typeof(name) === 'string'? name: "").trim() || Messages.anonymous; - }; + var getDisplayName = UI.getDisplayName; var makeMember = function (common, data, me, roster) { if (!data.curvePublic) { return; } From 7bb3bc167cdd340ab9bb192031e39fb011b8f247 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 15:12:28 +0530 Subject: [PATCH 11/20] use emoji avatars in share and access modals --- www/common/common-ui-elements.js | 36 +++++++++++++++++--------------- www/common/inner/access.js | 9 ++++++-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 6bb409222..d0ef0af3f 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -156,11 +156,11 @@ define([ var icons = Object.keys(users).map(function (key, i) { 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', { 'aria-hidden': true, // XXX aria }); - common.displayAvatar($(avatar), data.avatar, name); // XXX + common.displayAvatar($(avatar), data.avatar, name, Util.noop, data.uid); var removeBtn, el; if (config.remove) { removeBtn = h('span.fa.fa-times'); @@ -2014,13 +2014,12 @@ define([ return; } loadingAvatar = true; - var newName = myData.name; + var newName = UI.getDisplayName(myData.name); var url = myData.avatar; - $displayName.text(newName || Messages.anonymous); + $displayName.text(newName); if ((accountName && oldUrl !== url) || !accountName && uid !== oldUid) { $avatar.html(''); - Common.displayAvatar($avatar, url, - newName || Messages.anonymous, function ($img) { + Common.displayAvatar($avatar, url, newName, function ($img) { oldUrl = url; oldUid = uid; $userAdmin.find('> button').removeClass('cp-avatar'); @@ -2310,7 +2309,8 @@ define([ var teams = Object.keys(privateData.teams).map(function (id) { var data = privateData.teams[id]; var avatar = h('span.cp-creation-team-avatar.cp-avatar'); - common.displayAvatar($(avatar), data.avatar, data.name); // XXX + // We assume that teams always have a non-empty name, so we don't need a UID + common.displayAvatar($(avatar), data.avatar, data.name); return h('div.cp-creation-team', { 'data-id': id, title: data.name, @@ -3113,7 +3113,7 @@ define([ var sframeChan = common.getSframeChannel(); 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 text = Messages._getKey('owner_add', [name, title]); @@ -3245,7 +3245,7 @@ define([ var sframeChan = common.getSframeChannel(); 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 text = Messages._getKey('owner_team_add', [name, title]); @@ -3360,13 +3360,15 @@ define([ var verified = h('p'); var $verified = $(verified); + name = UI.getDisplayName(name); if (priv.friends && priv.friends[curve]) { $verified.addClass('cp-notifications-requestedit-verified'); var f = priv.friends[curve]; $verified.append(h('span.fa.fa-certificate')); var $avatar = $(h('span.cp-avatar')).appendTo($verified); - $verified.append(h('p', Messages._getKey('isContact', [f.displayName]))); - common.displayAvatar($avatar, f.avatar, f.displayName); + name = UI.getDisplayName(f.displayName); + $verified.append(h('p', Messages._getKey('isContact', [name]))); + common.displayAvatar($avatar, f.avatar, name, Util.noop, f.uid); } else { $verified.append(Messages._getKey('isNotContact', [name])); } @@ -3376,7 +3378,7 @@ define([ UIElements.displayInviteTeamModal = function (common, data) { 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 verified = UIElements.getVerifiedFriend(common, msg.author, name); @@ -3560,7 +3562,7 @@ define([ }; // Set the value to receive from the autocomplete var toInsert = function (data, key) { - var name = (data.name.replace(/[^a-zA-Z0-9]+/g, "-") || "").trim() || Messages.anonymous; // XXX + var name = UI.getDisplayName(data.name.replace(/[^a-zA-Z0-9]+/g, "-")); return "[@"+name+"|"+key+"]"; }; @@ -3614,7 +3616,7 @@ define([ contenteditable: false }); - var displayName = (data.name || "").trim() || Messages.anonymous; + var displayName = UI.getDisplayName(data.name); common.displayAvatar($(avatar), data.avatar, displayName); // XXX return h('span.cp-mentions', { 'data-curve': data.curvePublic, @@ -3658,7 +3660,7 @@ define([ }).map(function (key) { var data = sources[key]; return { - label: (data.name || "").trim() || Messages.anonymous, + label: UI.getDisplayName(data.name), value: key }; }); @@ -3693,9 +3695,9 @@ define([ var obj = sources[key]; if (!obj) { return; } var avatar = h('span.cp-avatar'); - var displayName = (obj.name || "").trim() || Messages.anonymous; + var displayName = UI.getDisplayName(obj.name); - common.displayAvatar($(avatar), obj.avatar, displayName, Util.noop, obj.uid); // XXX + common.displayAvatar($(avatar), obj.avatar, displayName, Util.noop, obj.uid); var li = h('li.cp-autocomplete-value', [ avatar, h('span', displayName), diff --git a/www/common/inner/access.js b/www/common/inner/access.js index 3f281dc47..119714de3 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -171,7 +171,7 @@ define([ if (!Object.keys(_friends).length) { var friendText; if (!friendKeys.length) { - console.error(UIElements.noContactsMessage(common)); + //console.error(UIElements.noContactsMessage(common)); var findContacts = UIElements.noContactsMessage(common); friendText = h('span.cp-app-prop-content', findContacts.content @@ -772,7 +772,8 @@ define([ if (friend.edPublic !== ed || c === 'me') { return; } _owners[friend.edPublic] = { name: friend.displayName, - avatar: friend.avatar + avatar: friend.avatar, + uid: friend.uid, }; return true; })) { @@ -782,6 +783,10 @@ define([ _owners[ed] = { avatar: '?', 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) }; strangers++; }); From 68efd549177bb5041dabce9170fc0bf8463182ee Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Aug 2021 16:18:09 +0530 Subject: [PATCH 12/20] include uid in cursor data for animal avatars --- www/code/inner.js | 4 +++- www/common/inner/common-mediatag.js | 9 +++++++-- www/common/sframe-common-codemirror.js | 1 + www/slide/inner.js | 4 +++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index 4f6c0308e..4328f0d8f 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -388,7 +388,9 @@ define([ var andThen2 = function (editor, CodeMirror, framework, isPresentMode) { var common = framework._.sfCommon; - var privateData = common.getMetadataMgr().getPrivateData(); + var metadataMgr = common.getMetadataMgr(); + var privateData = metadataMgr.getPrivateData(); + CodeMirror.uid = metadataMgr.getUserData().uid; var previewPane = mkPreviewPane(editor, CodeMirror, framework, isPresentMode); var markdownTb = mkMarkdownTb(editor, framework); diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 54b20784a..5e091a83c 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -43,9 +43,15 @@ define([ }); }; + var animal_avatars = {}; MT.getCursorAvatar = function (cursor) { + var uid = cursor.uid; var html = ''; - html += (cursor.avatar && avatars[cursor.avatar]) || ''; + if (cursor.avatar && avatars[cursor.avatar]) { + html += (cursor.avatar && avatars[cursor.avatar]) || ''; + } else if (animal_avatars[uid]) { + html += animal_avatars[uid] + ' '; + } html += Util.fixHTML(cursor.name) + ''; return html; }; @@ -109,7 +115,6 @@ define([ return text; }; - var animal_avatars = {}; MT.displayAvatar = function (common, $container, href, name, _cb, uid) { var cb = Util.once(Util.mkAsync(_cb || function () {})); var displayDefault = function () { diff --git a/www/common/sframe-common-codemirror.js b/www/common/sframe-common-codemirror.js index 58475bbed..4e490288d 100644 --- a/www/common/sframe-common-codemirror.js +++ b/www/common/sframe-common-codemirror.js @@ -509,6 +509,7 @@ define([ var cursor = {}; cursor.selectionStart = cursorToPos(editor.getCursor('from'), doc); cursor.selectionEnd = cursorToPos(editor.getCursor('to'), doc); + cursor.uid = exp.uid; // FIXME this is inefficient for the network but it's unlikely to trigger errors return cursor; }; diff --git a/www/slide/inner.js b/www/slide/inner.js index 143165176..9bbfc6e4d 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -459,7 +459,9 @@ define([ var andThen2 = function (editor, CodeMirror, framework, isPresentMode) { var common = framework._.sfCommon; - var privateData = common.getMetadataMgr().getPrivateData(); + var metadataMgr = common.getMetadataMgr(); + var privateData = metadataMgr.getPrivateData(); + CodeMirror.uid = metadataMgr.getUserData().uid; var $contentContainer = $('#cp-app-slide-editor'); var $modal = $('#cp-app-slide-modal'); From dd8f70d6f457e2a2afa30a710139ddb16fe26417 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 14:07:03 +0530 Subject: [PATCH 13/20] fix a bug I introduced by not preserving the base case of 'getAuthorId' --- www/common/sframe-common.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 01c48b540..000d049b3 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -252,10 +252,12 @@ define([ funcs.getAuthorId = function(authors, curve, tokenId) { var existing = Object.keys(authors || {}).map(Number); var uid; - if (!funcs.isLoggedIn()) { + var loggedIn = funcs.isLoggedIn(); + if (!loggedIn && !tokenId) { return authorUid(existing); } + if (!loggedIn) { existing.some(function (id) { - var author = authors[id] || {}; - if (author.uid !== tokenId) { return; } + var author = authors[id]; + if (!author || author.uid !== tokenId) { return; } uid = Number(id); return true; }); From bf02ec7359bb6dc048bcac928ee47b8d230f8a73 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 14:30:51 +0530 Subject: [PATCH 14/20] animal emojis in color-by-author 'written by' tooltips --- www/code/markers.js | 18 +++++++++++++++--- www/common/inner/common-mediatag.js | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/www/code/markers.js b/www/code/markers.js index b070e68fc..b8a53bdd9 100644 --- a/www/code/markers.js +++ b/www/code/markers.js @@ -3,7 +3,8 @@ define([ '/common/sframe-common-codemirror.js', '/customize/messages.js', '/bower_components/chainpad/chainpad.dist.js', -], function (Util, SFCodeMirror, Messages, ChainPad) { + '/common/inner/common-mediatag.js', +], function (Util, SFCodeMirror, Messages, ChainPad, MT) { var Markers = {}; /* TODO Known Issues @@ -38,7 +39,17 @@ define([ }); } uid = Number(uid); - var name = Util.fixHTML(author.name || Messages.anonymous); + var name = Util.fixHTML((author.name || "").trim()); + 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 rgba = 'rgba('+col[0]+','+col[1]+','+col[2]+','+Env.opacity+');'; return Env.editor.markText(from, to, { @@ -520,7 +531,8 @@ define([ Env.authormarks.authors[Env.myAuthorId] = { name: userData.name, curvePublic: userData.curvePublic, - color: userData.color + color: userData.color, + uid: userData.uid, }; if (!old || (old.name === userData.name && old.color === userData.color)) { return; } return true; diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 5e091a83c..db15d83d4 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -92,7 +92,7 @@ define([ return ANIMALS[Math.floor(Math.random() * ANIMALS.length)]; }; - var getPseudorandomAnimal = function (seed) { + var getPseudorandomAnimal = MT.getPseudorandomAnimal = function (seed) { if (typeof(seed) !== 'string') { return getRandomAnimal(); } seed = seed.replace(/\D/g, '').slice(0, 10); seed = parseInt(seed); From a701522c61b822bef3238ae2a0d6be57fed976b2 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 15:03:07 +0530 Subject: [PATCH 15/20] animal avatars for guests in join/part messages --- www/common/toolbar.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/www/common/toolbar.js b/www/common/toolbar.js index da8b1dad0..5b359a323 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -1217,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])); @@ -1277,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); } } } @@ -1297,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); } } } From 8a1f6d66cf3e7a12d7ab8b1b3142ecfd7dd1ab82 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 17:04:38 +0530 Subject: [PATCH 16/20] animal avatars in kanban cursors --- www/common/inner/common-mediatag.js | 3 ++- www/kanban/app-kanban.less | 8 ++++++ www/kanban/inner.js | 39 ++++++++++++++++++----------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index db15d83d4..e061667ce 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -46,6 +46,7 @@ define([ var animal_avatars = {}; 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 = ''; if (cursor.avatar && avatars[cursor.avatar]) { html += (cursor.avatar && avatars[cursor.avatar]) || ''; @@ -100,7 +101,7 @@ define([ return ANIMALS[seed % ANIMALS.length]; }; - var getPrettyInitials = function (name) { + var getPrettyInitials = MT.getPrettyInitials = function (name) { var parts = name.split(/\s+/); var text; if (parts.length > 1) { diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 69924ef77..098560548 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -159,6 +159,14 @@ margin-right: 5px; .tools_unselectable(); cursor: default; + &.cp-cursor.cp-tippy-html { + background-color: var(--red); + // XXX figure out how to inherit this from avatar.less + font-size: 11px; // 20px / 1.8 as per avatar.less.. + &.animal { + font-size: 14px; // 20px / 1.8 * (6/5)... + } + } } } .kanban-item { diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 42b1e39fa..fe80b1007 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -59,7 +59,7 @@ define([ verbose = function () {}; // comment out to enable verbose logging var onRedraw = Util.mkEvent(); var onCursorUpdate = Util.mkEvent(); - var remoteCursors = {}; // XXX + var remoteCursors = {}; var setValueAndCursor = function (input, val, _cursor) { if (!input) { return; } @@ -95,18 +95,27 @@ define([ var getAvatar = function (cursor, noClear) { // Tippy - var html = MT.getCursorAvatar(cursor); // XXX + var html = MT.getCursorAvatar(cursor); - var l = Util.getFirstCharacter(cursor.name || Messages.anonymous); + var name = UI.getDisplayName(cursor.name); + + var l; + var animal = ''; + if (cursor.name === Messages.anonymous && typeof(cursor.uid) === 'string') { + l = MT.getPseudorandomAnimal(cursor.uid); + animal = '.animal'; + } else { + 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', { // XXX - 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, // XXX "{0} is editing" + title: html, }, l); if (!noClear) { cursor.clear = function () { @@ -852,7 +861,7 @@ define([ getAvatar: getAvatar, openLink: openLink, getTags: getExistingTags, - cursors: remoteCursors, // XXX + cursors: remoteCursors, boards: boards, _boards: Util.clone(boards), }); @@ -1062,6 +1071,7 @@ define([ var kanban; var $container = $('#cp-app-kanban-content'); + var myData = framework._.cpNfInner.metadataMgr.getUserData(); var privateData = framework._.cpNfInner.metadataMgr.getPrivateData(); if (!privateData.isEmbed) { mkHelpMenu(framework); @@ -1101,7 +1111,7 @@ define([ $container.find('.kanban-edit-item').remove(); }); - var getCursor = function () { // XXX + var getCursor = function () { if (!kanban || !kanban.inEditMode) { return; } try { var id = kanban.inEditMode; @@ -1204,7 +1214,7 @@ define([ var remoteContent = newContent.content; if (Sortify(currentContent) !== Sortify(remoteContent)) { - var cursor = getCursor(); // XXX + var cursor = getCursor(); verbose("Content is different.. Applying content"); kanban.options.boards = remoteContent; updateBoards(framework, kanban, remoteContent); @@ -1261,11 +1271,13 @@ define([ }); var myCursor = {}; - onCursorUpdate.reg(function (data) { // XXX + onCursorUpdate.reg(function (data) { + console.log('onCursorUpdate', data); myCursor = data; + myCursor.uid = myData.uid; framework.updateCursor(); }); - framework.onCursorUpdate(function (data) { // XXX + framework.onCursorUpdate(function (data) { if (!data) { return; } if (data.reset) { Object.keys(remoteCursors).forEach(function (id) { @@ -1293,9 +1305,8 @@ define([ if (!cursor.item && !cursor.board) { return; } // Add new cursor - var avatar = getAvatar(cursor); // XXX + 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); From 840a16a563c2c1b96c6449db8b2adee398d70f7a Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 17:39:56 +0530 Subject: [PATCH 17/20] add animal emojis to rich text cursors' tooltips --- www/pad/cursor.js | 21 ++++++++++++++++++--- www/pad/inner.js | 3 ++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/www/pad/cursor.js b/www/pad/cursor.js index 42569838f..fbca1a9cf 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) { @@ -35,13 +37,20 @@ define([ $(el).remove(); }; - Cursor.create = function (inner, hjsonToDom, cursorModule) { + Cursor.create = function (inner, hjsonToDom, cursorModule, uid) { var exp = {}; 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; + //return cursor.name; + if (typeof(cursor.uid) === 'string' && (!cursor.name || cursor.name === Messages.anonymous)) { + return MT.getPseudorandomAnimal(cursor.uid) + ' ' + Messages.anonymous; + } + return cursor.name || Messages.anonymous; }; var makeCursor = function (id, cursor) { @@ -138,6 +147,12 @@ define([ var cursorObj = data.cursor; if (!cursorObj.selectionStart) { return; } + if (cursorObj.name === Messages.anonymous) { + // save a little bit of data from going over the wire... + // remote clients will interpret this as Messages.anonymous (in their UI language) + cursorObj.name = ''; + cursorObj.uid = uid; + } // 1. Transform the cursor to get the offset relative to our doc // 2. Turn it into a range diff --git a/www/pad/inner.js b/www/pad/inner.js index 95e7c1bff..e89cd9a0a 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -678,6 +678,7 @@ define([ var metadataMgr = framework._.sfCommon.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); + var myData = metadataMgr.getUserData(); var common = framework._.sfCommon; var APP = window.APP; @@ -704,7 +705,7 @@ define([ var cursor = module.cursor = Cursor(inner); // Display other users cursor - var cursors = Cursors.create(inner, hjsonToDom, cursor); + var cursors = Cursors.create(inner, hjsonToDom, cursor, myData.uid); var openLink = function(e) { var el = e.currentTarget; From 1e1890dbe4a4dcaba56c703488ca9dec11c713fb Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 17:42:22 +0530 Subject: [PATCH 18/20] replace a line that I accidentally removed --- www/kanban/inner.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index fe80b1007..6934dd210 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -1312,6 +1312,7 @@ define([ $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); From c416303e1d3f9d9fb74821abedf23141e23b8b44 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 27 Aug 2021 18:23:07 +0530 Subject: [PATCH 19/20] set uid in cursor object in outer scope rather than within each app that uses cursors --- www/code/inner.js | 4 +--- www/code/markers.js | 5 +++-- www/common/outer/cursor.js | 1 + www/common/sframe-common-codemirror.js | 1 - www/kanban/inner.js | 2 -- www/pad/cursor.js | 8 +------- www/pad/inner.js | 3 +-- www/slide/inner.js | 6 ++---- 8 files changed, 9 insertions(+), 21 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index 4328f0d8f..4f6c0308e 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -388,9 +388,7 @@ define([ var andThen2 = function (editor, CodeMirror, framework, isPresentMode) { var common = framework._.sfCommon; - var metadataMgr = common.getMetadataMgr(); - var privateData = metadataMgr.getPrivateData(); - CodeMirror.uid = metadataMgr.getUserData().uid; + var privateData = common.getMetadataMgr().getPrivateData(); var previewPane = mkPreviewPane(editor, CodeMirror, framework, isPresentMode); var markdownTb = mkMarkdownTb(editor, framework); diff --git a/www/code/markers.js b/www/code/markers.js index b8a53bdd9..48e5a25fb 100644 --- a/www/code/markers.js +++ b/www/code/markers.js @@ -4,7 +4,8 @@ define([ '/customize/messages.js', '/bower_components/chainpad/chainpad.dist.js', '/common/inner/common-mediatag.js', -], function (Util, SFCodeMirror, Messages, ChainPad, MT) { + '/common/common-interface.js', +], function (Util, SFCodeMirror, Messages, ChainPad, MT, UI) { var Markers = {}; /* TODO Known Issues @@ -39,7 +40,7 @@ define([ }); } uid = Number(uid); - var name = Util.fixHTML((author.name || "").trim()); + var name = Util.fixHTML(UI.getDisplayName(author.name)); var animal; if ((!name || name === Messages.anonymous) && typeof(author.uid) === 'string') { animal = MT.getPseudorandomAnimal(author.uid); 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-codemirror.js b/www/common/sframe-common-codemirror.js index 4e490288d..58475bbed 100644 --- a/www/common/sframe-common-codemirror.js +++ b/www/common/sframe-common-codemirror.js @@ -509,7 +509,6 @@ define([ var cursor = {}; cursor.selectionStart = cursorToPos(editor.getCursor('from'), doc); cursor.selectionEnd = cursorToPos(editor.getCursor('to'), doc); - cursor.uid = exp.uid; // FIXME this is inefficient for the network but it's unlikely to trigger errors return cursor; }; diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 6934dd210..368d18139 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -1272,9 +1272,7 @@ define([ var myCursor = {}; onCursorUpdate.reg(function (data) { - console.log('onCursorUpdate', data); myCursor = data; - myCursor.uid = myData.uid; framework.updateCursor(); }); framework.onCursorUpdate(function (data) { diff --git a/www/pad/cursor.js b/www/pad/cursor.js index fbca1a9cf..5b4c60ad7 100644 --- a/www/pad/cursor.js +++ b/www/pad/cursor.js @@ -37,7 +37,7 @@ define([ $(el).remove(); }; - Cursor.create = function (inner, hjsonToDom, cursorModule, uid) { + Cursor.create = function (inner, hjsonToDom, cursorModule) { var exp = {}; var cursors = {}; @@ -147,12 +147,6 @@ define([ var cursorObj = data.cursor; if (!cursorObj.selectionStart) { return; } - if (cursorObj.name === Messages.anonymous) { - // save a little bit of data from going over the wire... - // remote clients will interpret this as Messages.anonymous (in their UI language) - cursorObj.name = ''; - cursorObj.uid = uid; - } // 1. Transform the cursor to get the offset relative to our doc // 2. Turn it into a range diff --git a/www/pad/inner.js b/www/pad/inner.js index e89cd9a0a..95e7c1bff 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -678,7 +678,6 @@ define([ var metadataMgr = framework._.sfCommon.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); - var myData = metadataMgr.getUserData(); var common = framework._.sfCommon; var APP = window.APP; @@ -705,7 +704,7 @@ define([ var cursor = module.cursor = Cursor(inner); // Display other users cursor - var cursors = Cursors.create(inner, hjsonToDom, cursor, myData.uid); + var cursors = Cursors.create(inner, hjsonToDom, cursor); var openLink = function(e) { var el = e.currentTarget; diff --git a/www/slide/inner.js b/www/slide/inner.js index 9bbfc6e4d..9c9b9c70b 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -459,9 +459,7 @@ define([ var andThen2 = function (editor, CodeMirror, framework, isPresentMode) { var common = framework._.sfCommon; - var metadataMgr = common.getMetadataMgr(); - var privateData = metadataMgr.getPrivateData(); - CodeMirror.uid = metadataMgr.getUserData().uid; + var privateData = common.getMetadataMgr().getPrivateData(); var $contentContainer = $('#cp-app-slide-editor'); var $modal = $('#cp-app-slide-modal'); @@ -513,7 +511,7 @@ define([ framework.updateCursor(); }, 500); // 500ms to make sure it is sent after chainpad sync }; - framework.onCursorUpdate(CodeMirror.setRemoteCursor); // XXX + framework.onCursorUpdate(CodeMirror.setRemoteCursor); framework.setCursorGetter(CodeMirror.getCursor); editor.on('cursorActivity', updateCursor); From cd613f10377c655340d7534c61ee9868f1c81fd2 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 27 Aug 2021 19:38:50 +0530 Subject: [PATCH 20/20] many small improvements for animal avatars * more consistent scaling for animal avatars relative to the font-size of username's initials * configurable emoji lists via AppConfig.emojiAvatars * various comments from code review * fixed a bug that caused the user admin menu button to not be redrawn on name changes * guard against empty animal emojis in case the admin sets the list to [] --- customize.dist/src/less2/include/avatar.less | 10 ++++---- customize.dist/src/less2/include/toolbar.less | 7 +++++- www/common/application_config_internal.js | 2 ++ www/common/common-messaging.js | 2 +- www/common/common-ui-elements.js | 4 ++- www/common/inner/access.js | 1 + www/common/inner/common-mediatag.js | 25 ++++++++++--------- www/kanban/app-kanban.less | 5 ++-- www/kanban/inner.js | 10 +++++--- www/pad/cursor.js | 6 +++-- 10 files changed, 44 insertions(+), 28 deletions(-) diff --git a/customize.dist/src/less2/include/avatar.less b/customize.dist/src/less2/include/avatar.less index 079ceb60d..acaa13351 100644 --- a/customize.dist/src/less2/include/avatar.less +++ b/customize.dist/src/less2/include/avatar.less @@ -5,6 +5,10 @@ ) { @avatar-width: @width; @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) { --LessLoader_require: LessLoader_currentFile(); @@ -41,11 +45,7 @@ font-size: @avatar-font-size; font-size: var(--avatar-font-size); .animal { - font-size: 20px; - // 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 - font-size: calc(var(--avatar-width) * (6/5)); + font-size: @avatar-font-size-animal; } } media-tag { diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 28b513095..2092d72cc 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -855,10 +855,15 @@ span { text-align: center; width: 100%; - font-size: 40px; + .avatar_vars(72px); + font-size: @avatar-font-size; display: inline-flex; justify-content: center; align-items: center; + .animal { + font-size: @avatar-font-size-animal; + + } } &.cp-avatar { .avatar_main(64px); diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 3be979f17..2993edc52 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -208,5 +208,7 @@ define(function() { // the driveless mode by changing the following value to "false" AppConfig.allowDrivelessMode = true; + AppConfig.emojiAvatars = '🙈 đŸĻ€ 🐞 đŸĻ‹ đŸŦ 🐋 đŸĸ đŸĻ‰ đŸĻ† 🐧 đŸĻĄ đŸĻ˜ đŸĻ¨ đŸĻĻ đŸĻĨ đŸŧ đŸģ đŸĻ đŸĻ“ 🐄 🐷 🐐 đŸĻ™ đŸĻ’ 🐘 đŸĻ 🐁 🐹 🐰 đŸĻĢ đŸĻ” 🐨 🐱 đŸē đŸ‘ē 👹 đŸ‘Ŋ 👾 🤖'.split(/\s+/); + return AppConfig; }); diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index 4a3eb2a91..1e6e26ce3 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -18,7 +18,7 @@ define([ curvePublic: proxy.curvePublic, notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']), avatar: proxy.profile && proxy.profile.avatar, - uid: proxy.uid, + uid: proxy.uid, // XXX test without this and see if it breaks things }; if (hash === false) { delete data.channel; } return data; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index d0ef0af3f..abf45b0bd 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1996,6 +1996,7 @@ define([ var to; var oldUrl = ''; var oldUid; + var oldName; var updateButton = function () { var myData = metadataMgr.getUserData(); var privateData = metadataMgr.getPrivateData(); @@ -2017,11 +2018,12 @@ define([ var newName = UI.getDisplayName(myData.name); var url = myData.avatar; $displayName.text(newName); - if ((accountName && oldUrl !== url) || !accountName && uid !== oldUid) { + if ((accountName && oldUrl !== url) || !accountName && uid !== oldUid || oldName !== newName) { $avatar.html(''); Common.displayAvatar($avatar, url, newName, function ($img) { oldUrl = url; oldUid = uid; + oldName = newName; $userAdmin.find('> button').removeClass('cp-avatar'); if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); } loadingAvatar = false; diff --git a/www/common/inner/access.js b/www/common/inner/access.js index 119714de3..0ba857a0a 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -787,6 +787,7 @@ define([ // 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++; }); diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index e061667ce..21cb25e82 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -6,12 +6,13 @@ define([ '/common/hyperscript.js', '/common/media-tag.js', '/customize/messages.js', + '/customize/application_config.js', '/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/croppie/croppie.min.js', '/bower_components/file-saver/FileSaver.min.js', 'css!/bower_components/croppie/croppie.css', -], function ($, Util, Hash, UI, h, MediaTag, Messages) { +], function ($, Util, Hash, UI, h, MediaTag, Messages, AppConfig) { var MT = {}; var Nacl = window.nacl; @@ -49,7 +50,7 @@ define([ // TODO it would be nice to have "{0} is editing" instead of just their name var html = ''; if (cursor.avatar && avatars[cursor.avatar]) { - html += (cursor.avatar && avatars[cursor.avatar]) || ''; + html += avatars[cursor.avatar]; } else if (animal_avatars[uid]) { html += animal_avatars[uid] + ' '; } @@ -87,18 +88,20 @@ define([ }; // https://emojipedia.org/nature/ - var ANIMALS = '🙈 đŸĻ€ 🐞 đŸĻ‹ đŸŦ 🐋 đŸĸ đŸĻ‰ đŸĻ† 🐧 đŸĻĄ đŸĻ˜ đŸĻ¨ đŸĻĻ đŸĻĨ đŸŧ đŸģ đŸĻ đŸĻ“ 🐄 🐷 🐐 đŸĻ™ đŸĻ’ 🐘 đŸĻ 🐁 🐹 🐰 đŸĻĢ đŸĻ” 🐨 🐱 đŸē đŸ‘ē 👹 đŸ‘Ŋ 👾 🤖'.split(/\s+/); + var ANIMALS = AppConfig.emojiAvatars || []; - var getRandomAnimal = function () { + 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); + 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]; + return ANIMALS[seed % ANIMALS.length] || ''; }; var getPrettyInitials = MT.getPrettyInitials = function (name) { @@ -123,29 +126,27 @@ define([ if (uid && animal_avatars[uid]) { animal_avatar = animal_avatars[uid]; } - var animal = false; - name = (name || "").trim() || Messages.anonymous; + name = UI.getDisplayName(name); var text; - if (name === Messages.anonymous && uid) { + if (ANIMALS.length && name === Messages.anonymous && uid) { if (animal_avatar) { text = animal_avatar; } else { text = animal_avatar = getPseudorandomAnimal(uid); } - animal = true; } else { text = getPrettyInitials(name); } var $avatar = $('', { - 'class': 'cp-avatar-default' + (animal? ' animal': ''), + 'class': 'cp-avatar-default' + (animal_avatar? ' animal': ''), // XXX prevents screenreaders from trying to describe this alt: '', 'aria-hidden': true, }).text(text); $container.append($avatar); - if (uid && animal) { + if (uid && animal_avatar) { animal_avatars[uid] = animal_avatar; } if (cb) { cb(); } diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 098560548..5996940e4 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -160,11 +160,12 @@ .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: 11px; // 20px / 1.8 as per avatar.less.. + font-size: @avatar-font-size; //var(11px; // 20px / 1.8 as per avatar.less.. &.animal { - font-size: 14px; // 20px / 1.8 * (6/5)... + font-size: @avatar-font-size-animal; //14px; // 20px / 1.8 * (6/5)... } } } diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 368d18139..add0ed693 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -99,12 +99,15 @@ define([ var name = UI.getDisplayName(cursor.name); - var l; + var l; // label? var animal = ''; if (cursor.name === Messages.anonymous && typeof(cursor.uid) === 'string') { l = MT.getPseudorandomAnimal(cursor.uid); - animal = '.animal'; - } else { + if (l) { + animal = '.animal'; + } + } + if (!l) { l = MT.getPrettyInitials(name); } @@ -1071,7 +1074,6 @@ define([ var kanban; var $container = $('#cp-app-kanban-content'); - var myData = framework._.cpNfInner.metadataMgr.getUserData(); var privateData = framework._.cpNfInner.metadataMgr.getPrivateData(); if (!privateData.isEmbed) { mkHelpMenu(framework); diff --git a/www/pad/cursor.js b/www/pad/cursor.js index 5b4c60ad7..ae91c80f1 100644 --- a/www/pad/cursor.js +++ b/www/pad/cursor.js @@ -46,9 +46,11 @@ define([ // 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)) { - return MT.getPseudorandomAnimal(cursor.uid) + ' ' + Messages.anonymous; + var animal = MT.getPseudorandomAnimal(cursor.uid); + if (animal) { + return animal + ' ' + Messages.anonymous; + } } return cursor.name || Messages.anonymous; };