From 1e003b13a88a94f42a87707e29b53b0c24f4c78e Mon Sep 17 00:00:00 2001 From: Yann Flory Date: Fri, 21 Oct 2016 15:17:15 +0200 Subject: [PATCH 1/6] ask anonymous, first-time users to set their name when they first join a pad --- customize.dist/translations/messages.fr.js | 1 + customize.dist/translations/messages.js | 2 +- www/code/main.js | 11 +++++++---- www/common/cryptpad-common.js | 3 +-- www/pad/main.js | 15 +++++++++------ www/slide/main.js | 11 +++++++---- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 31b435f1e..3d4f85196 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -45,6 +45,7 @@ define(function () { out.userButton = 'UTILISATEUR'; out.userButtonTitle = "Changer votre nom d'utilisateur"; + out.changeNamePrompt = 'Changer votre nom (laisser vide pour rester anonyme) : '; out.renameButton = 'RENOMMER'; out.renameButtonTitle = 'Changer le titre utilisé par ce document dans la page d\'accueil de Cryptpad'; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 2b2a7a0cb..51c8f73a7 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -45,7 +45,7 @@ define(function () { out.userButton = 'USER'; out.userButtonTitle = 'Change your username'; - out.changeNamePrompt = 'Change your name: '; + out.changeNamePrompt = 'Change your name (leave empty to be anonymous): '; out.renameButton = 'RENAME'; out.renameButtonTitle = 'Change the title under which this document is listed on your home page'; diff --git a/www/code/main.js b/www/code/main.js index 1e4a11758..1fb9897b0 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -198,6 +198,7 @@ define([ console.error(err); return; } + module.userName.lastName = myUserName; onLocal(); }); }; @@ -321,12 +322,12 @@ define([ editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); } + // Store the object sent for the "change username" button so that we can update the field value correctly + var userNameButtonObject = module.userName = {}; /* add a "change username" button */ getLastName(function (err, lastName) { - var usernameCb = function (newName) { - setName (newName); - }; - var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb); + userNameButtonObject.lastName = lastName; + var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName); $userBlock.append($username).hide(); }); @@ -555,6 +556,8 @@ define([ addToUserList(myData); if (typeof(lastName) === 'string' && lastName.length) { setName(lastName); + } else { + module.$userNameButton.click(); } onLocal(); }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index b512ab54b..bd4519562 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -719,9 +719,8 @@ define([ title: Messages.userButton + '\n' + Messages.userButtonTitle }).html(''); if (data && typeof data.lastName !== "undefined" && callback) { - var lastName = data.lastName; button.click(function() { - common.prompt(Messages.changeNamePrompt, lastName, function (newName) { + common.prompt(Messages.changeNamePrompt, data.lastName, function (newName) { callback(newName); }); }); diff --git a/www/pad/main.js b/www/pad/main.js index 78b49fc8f..ea1d3d496 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -291,12 +291,13 @@ define([ name: myUserName }; addToUserList(myData); - editor.fire('change'); - Cryptpad.setAttribute('username', newName, function (err, data) { if (err) { console.error("Couldn't set username"); + return; } + module.userName.lastName = myUserName; + editor.fire('change'); }); }; @@ -535,12 +536,12 @@ define([ editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); } + // Store the object sent for the "change username" button so that we can update the field value correctly + var userNameButtonObject = module.userName = {}; /* add a "change username" button */ getLastName(function (err, lastName) { - var usernameCb = function (newName) { - setName (newName); - }; - var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb); + userNameButtonObject.lastName = lastName; + var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName); $userBlock.append($username).hide(); }); @@ -638,6 +639,8 @@ define([ addToUserList(myData); if (typeof(lastName) === 'string' && lastName.length) { setName(lastName); + } else { + module.$userNameButton.click(); } realtimeOptions.onLocal(); }); diff --git a/www/slide/main.js b/www/slide/main.js index ef7246b18..e5ca84317 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -246,6 +246,7 @@ define([ console.error(err); return; } + module.userName.lastName = myUserName; onLocal(); }); }; @@ -398,12 +399,12 @@ define([ editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); } + // Store the object sent for the "change username" button so that we can update the field value correctly + var userNameButtonObject = module.userName = {}; /* add a "change username" button */ getLastName(function (err, lastName) { - var usernameCb = function (newName) { - setName (newName); - }; - var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb); + userNameButtonObject.lastName = lastName; + var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName); $userBlock.append($username).hide(); }); @@ -655,6 +656,8 @@ define([ addToUserList(myData); if (typeof(lastName) === 'string' && lastName.length) { setName(lastName); + } else { + module.$userNameButton.click(); } onLocal(); }); From 10bb5e1607cc690b458788dc322e87ff36b22e27 Mon Sep 17 00:00:00 2001 From: Yann Flory Date: Fri, 21 Oct 2016 18:16:27 +0200 Subject: [PATCH 2/6] Add the title in the toolbar --- customize.dist/src/toolbar.less | 28 +++++++++++++++++ customize.dist/toolbar.css | 28 +++++++++++++++++ www/common/cryptpad-common.js | 56 +++++++++++++++++---------------- www/common/toolbar.js | 34 ++++++++++++++++++++ www/pad/main.js | 26 +++++++-------- 5 files changed, 131 insertions(+), 41 deletions(-) diff --git a/customize.dist/src/toolbar.less b/customize.dist/src/toolbar.less index 17e25c232..9832fc0a9 100644 --- a/customize.dist/src/toolbar.less +++ b/customize.dist/src/toolbar.less @@ -105,6 +105,34 @@ } } +.cryptpad-toolbar-top { + display: block; + text-align: center; + .cryptpad-title { + text-align: center; + input { + border: 1px solid black; + background: #fff; + cursor: auto; + width: 300px; + padding: 5px; + -webkit-touch-callout: text; + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + &:focus { + -webkit-touch-callout: text; + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + } + } + } +} .cryptpad-toolbar-leftside { float: left; margin-bottom: -1px; diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index 930a17eaf..9cbde4f5d 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -101,6 +101,34 @@ border: 1px solid #A6A6A6; border-bottom-color: #979797; } +.cryptpad-toolbar-top { + display: block; + text-align: center; +} +.cryptpad-toolbar-top .cryptpad-title { + text-align: center; +} +.cryptpad-toolbar-top .cryptpad-title input { + border: 1px solid black; + background: #fff; + cursor: auto; + width: 300px; + padding: 5px; + -webkit-touch-callout: text; + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} +.cryptpad-toolbar-top .cryptpad-title input:focus { + -webkit-touch-callout: text; + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} .cryptpad-toolbar-leftside { float: left; margin-bottom: -1px; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index b512ab54b..b6d5f1588 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -619,6 +619,32 @@ define([ /* * Buttons */ + var renamePad = common.renamePad = function (title, callback) { + if (title === null) { return; } + + common.causesNamingConflict(title, function (err, conflicts) { + if (err) { + console.log("Unable to determine if name caused a conflict"); + console.error(err); + callback(err, title); + return; + } + + if (conflicts) { + common.alert(Messages.renameConflict); + return; + } + + common.setPadTitle(title, function (err, data) { + if (err) { + console.log("unable to set pad title"); + console.log(err); + return; + } + callback(null, title); + }); + }); + }; var createButton = common.createButton = function (type, rightside, data, callback) { var button; var size = "17px"; @@ -657,33 +683,9 @@ define([ button.click(function() { var suggestion = suggestName(); - common.prompt(Messages.renamePrompt, - suggestion, function (title, ev) { - if (title === null) { return; } - - common.causesNamingConflict(title, function (err, conflicts) { - if (err) { - console.log("Unable to determine if name caused a conflict"); - console.error(err); - callback(err, title); - return; - } - - if (conflicts) { - common.alert(Messages.renameConflict); - return; - } - - common.setPadTitle(title, function (err, data) { - if (err) { - console.log("unable to set pad title"); - console.log(err); - return; - } - callback(null, title); - }); - }); - }); + common.prompt(Messages.renamePrompt, suggestion, function (title, ev) { + renamePad(title, callback); + }); }); } break; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 943e27df5..bd58f324a 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -17,6 +17,7 @@ define([ /** The toolbar class which contains the user list, debug link and lag. */ var TOOLBAR_CLS = Bar.constants.toolbar = 'cryptpad-toolbar'; + var TOP_CLS = Bar.constants.top = 'cryptpad-toolbar-top'; var LEFTSIDE_CLS = Bar.constants.leftside = 'cryptpad-toolbar-leftside'; var RIGHTSIDE_CLS = Bar.constants.rightside = 'cryptpad-toolbar-rightside'; @@ -34,6 +35,7 @@ define([ var VIEWSHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-viewShare"; var DROPDOWN_CONTAINER_CLS = Bar.constants.dropdownContainer = "cryptpad-dropdown-container"; var DROPDOWN_CLS = Bar.constants.dropdown = "cryptpad-dropdown"; + var TITLE_CLS = Bar.constants.title = "cryptpad-title"; /** Key in the localStore which indicates realtime activity should be disallowed. */ // TODO remove? will never be used in cryptpad @@ -67,6 +69,7 @@ define([ 'class': TOOLBAR_CLS, id: uid(), }) + .append($('
', {'class': TOP_CLS})) .append($('
', {'class': LEFTSIDE_CLS})) .append($('
', {'class': RIGHTSIDE_CLS})); @@ -300,6 +303,36 @@ define([ $(lagElement).append(lagLight); }; + var createTitle = function ($container, readOnly, cb) { + var $titleContainer = $('', { + id: 'toolbarTitle', + 'class': TITLE_CLS + }).appendTo($container); + var $text = $('').appendTo($titleContainer); + if (readOnly === 1) { return; } + var $input = $('', { + type: 'text' + }).appendTo($titleContainer).hide(); + $input.on('keyup', function (e) { + if (e.which === 13) { + Cryptpad.renamePad(title, function (err, newtitle) { + if (err) { return; } + $text.text(newtitle); + cb(null, newtitle); + $input.hide(); + $text.show(); + }); + } + }); + $text.on('click', function () { + console.log('click'); + $text.hide(); + $input.val($text.text()); + $input.show(); + $input.focus(); + }); + }; + var create = Bar.create = function ($container, myUserName, realtime, getLag, userList, config) { var readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1; @@ -307,6 +340,7 @@ define([ var userListElement = createUserList(toolbar.find('.' + LEFTSIDE_CLS), readOnly); var spinner = createSpinner(toolbar.find('.' + RIGHTSIDE_CLS)); var lagElement = createLagElement(toolbar.find('.' + RIGHTSIDE_CLS)); + var $titleElement = createTitle(toolbar.find('.' + TOP_CLS), readOnly, config.onRename); var userData = config.userData; // readOnly = 1 (readOnly enabled), 0 (disabled), -1 (old pad without readOnly mode) var saveElement; diff --git a/www/pad/main.js b/www/pad/main.js index 78b49fc8f..d6f3fdef5 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -85,11 +85,12 @@ define([ }); editor.on('instanceReady', function (Ckeditor) { + var $bar = $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox'); + if (readOnly) { $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox > .cke_toolbar').hide(); } - /* add a class to the magicline plugin so we can pick it out more easily */ var ml = $('iframe')[0].contentWindow.CKEDITOR.instances.editor1.plugins.magicline @@ -402,6 +403,7 @@ define([ document.title = oldTitle; return; } + $bar.find('.' + Toolbar.constants.title).find('span').text(newTitle); }); }; @@ -512,13 +514,19 @@ define([ realtimeOptions.onLocal(); }; + var renameCb = function (err, title) { + if (err) { return; } + document.title = title; + editor.fire('change'); + }; + var onInit = realtimeOptions.onInit = function (info) { - var $bar = $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox'); toolbarList = info.userList; var config = { userData: userList, readOnly: readOnly, - ifrw: ifrw + ifrw: ifrw, + onRename: renameCb }; if (readOnly) {delete config.changeNameID; } toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); @@ -554,11 +562,6 @@ define([ $rightside.append($import); /* add a rename button */ - var renameCb = function (err, title) { - if (err) { return; } - document.title = title; - editor.fire('change'); - }; var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb); $rightside.append($setTitle); } @@ -593,13 +596,8 @@ define([ console.log("Couldn't get pad title"); return; } + updateTitle(title || info.channel.slice(0, 8)); document.title = title || info.channel.slice(0, 8); - Cryptpad.setPadTitle(title, function (err, data) { - if (err) { - console.log("Couldn't remember pad"); - console.error(err); - } - }); }); }; From ac3ddbab70a4a49b16e4e5a1fe6440ac2bb1a2f9 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 15:10:49 +0200 Subject: [PATCH 3/6] expose userList for later usage --- www/poll/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/poll/main.js b/www/poll/main.js index a586fc502..698cb9adc 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -475,6 +475,9 @@ define([ setEditable(false); var ready = function (info) { + console.log(info); + module.users = info.userList.users; + console.log("Your realtime object is ready"); module.ready = true; From c858b247c11ecf07ba232b13a8d8eb7d426aa525 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 15:11:19 +0200 Subject: [PATCH 4/6] filter absent users from the userlist --- www/code/main.js | 12 +++++++++++- www/slide/main.js | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/www/code/main.js b/www/code/main.js index 1fb9897b0..586910ac0 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -112,9 +112,18 @@ define([ editor.setOption('readOnly', !bool); }; - var userList = {}; // List of pretty name of all users (mapped with their server ID) + var userList = module.userList = {}; // List of pretty name of all users (mapped with their server ID) var toolbarList; // List of users still connected to the channel (server IDs) var addToUserList = function(data) { + var users = module.users; + if (users && users.length) { + for (var userKey in userList) { + if (users.indexOf(userKey) === -1) { + delete userList[userKey]; + } + } + } + for (var attrname in data) { userList[attrname] = data[attrname]; } if(toolbarList && typeof toolbarList.onChange === "function") { toolbarList.onChange(userList); @@ -502,6 +511,7 @@ define([ var onReady = config.onReady = function (info) { var realtime = module.realtime = info.realtime; + module.users = info.userList.users; module.patchText = TextPatcher.create({ realtime: realtime, //logging: true diff --git a/www/slide/main.js b/www/slide/main.js index e5ca84317..cad8adc5c 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -149,9 +149,18 @@ define([ editor.setOption('readOnly', !bool); }; - var userList = {}; // List of pretty name of all users (mapped with their server ID) + var userList = module.userList = {}; // List of pretty name of all users (mapped with their server ID) var toolbarList; // List of users still connected to the channel (server IDs) var addToUserList = function(data) { + var users = module.users; + if (users && users.length) { + for (var userKey in userList) { + if (users.indexOf(userKey) === -1) { + delete userList[userKey]; + } + } + } + for (var attrname in data) { userList[attrname] = data[attrname]; } if(toolbarList && typeof toolbarList.onChange === "function") { toolbarList.onChange(userList); @@ -592,6 +601,7 @@ define([ var onReady = config.onReady = function (info) { var realtime = module.realtime = info.realtime; + module.users = info.userList.users; module.patchText = TextPatcher.create({ realtime: realtime, //logging: true From 0a9d34a6c9e4db1ea42261c85315e096ad370cdf Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 15:29:46 +0200 Subject: [PATCH 5/6] hide appended color pickers --- www/slide/main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/slide/main.js b/www/slide/main.js index cad8adc5c..a5c41633a 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -531,6 +531,7 @@ define([ if ($testColor.attr('type') !== "color" || $testColor.val() === '!') { return; } // TODO $back.on('click', function() { var $picker = $('', { type: 'color', value: backColor }) + .css({ display: 'none', }) .on('change', function() { updateColors(undefined, this.value); onLocal(); @@ -542,6 +543,7 @@ define([ }); $text.on('click', function() { var $picker = $('', { type: 'color', value: textColor }) + .css({ display: 'none', }) .on('change', function() { updateColors(this.value, undefined); onLocal(); From 636b0fcadc3e3e2d6da0df4db192c42565d52498 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 2 Nov 2016 12:09:41 +0100 Subject: [PATCH 6/6] do our best to keep the console quiet --- www/poll/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/poll/main.js b/www/poll/main.js index 698cb9adc..bbe3fc97b 100644 --- a/www/poll/main.js +++ b/www/poll/main.js @@ -475,7 +475,6 @@ define([ setEditable(false); var ready = function (info) { - console.log(info); module.users = info.userList.users; console.log("Your realtime object is ready");