From 1e003b13a88a94f42a87707e29b53b0c24f4c78e Mon Sep 17 00:00:00 2001 From: Yann Flory Date: Fri, 21 Oct 2016 15:17:15 +0200 Subject: [PATCH 01/21] 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 02/21] 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 2326526f95713229602a78bdafb36ce2c7fb7bfc Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 14:32:34 +0200 Subject: [PATCH 03/21] correct grammatical error in French translation --- customize.dist/translations/messages.fr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 31b435f1e..7dd8b5bcd 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -146,7 +146,7 @@ define(function () { // index.html - out.main_p1 = 'CryptPad est l\'éditeur collaboratif en temps réel zero knowledge. Le chiffrement est effectué depuis votre navigateur, ce qui protège les données contre le serveur, le cloud, et la NSA. La clé de chiffrement est stockée dans l\'identifieur de fragment de l\'URL qui n\'est jamais envoyée au serveur mais est accessible depuis javascript, de sorte qu\'en partageant l\'URL, vous donner l\'accès au pad à ceux qui souhaitent participer.'; + out.main_p1 = 'CryptPad est l\'éditeur collaboratif en temps réel zero knowledge. Le chiffrement est effectué depuis votre navigateur, ce qui protège les données contre le serveur, le cloud, et la NSA. La clé de chiffrement est stockée dans l\'identifieur de fragment de l\'URL qui n\'est jamais envoyée au serveur mais est accessible depuis javascript, de sorte qu\'en partageant l\'URL, vous donnez l\'accès au pad à ceux qui souhaitent participer.'; out.main_p2 = 'Ce projet utilise l\'éditeur visuel (WYSIWYG) CKEditor, l\'éditeur de code source CodeMirror, et le moteur temps-réel ChainPad.'; out.main_howitworks = 'Comment ça fonctionne'; out.main_howitworks_p1 = 'CryptPad utilise une variante de l\'algorithme d\'Operational transformation qui est capable de trouver un consensus distribué en utilisant une chaîne de bloc Nakamoto, un outil popularisé par le Bitcoin. De cette manière, l\'algorithme évite la nécessité d\'utiliser un serveur central pour résoudre les conflits d\'édition de l\'Operational Transformation, et sans ce besoin de résolution des conflits le serveur peut rester ignorant du contenu qui est édité dans le pad.'; From ac3ddbab70a4a49b16e4e5a1fe6440ac2bb1a2f9 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 15:10:49 +0200 Subject: [PATCH 04/21] 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 05/21] 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 5dbd16a95655937706b26b8e89c977307d274831 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 15:29:46 +0200 Subject: [PATCH 06/21] 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 ef7246b18..1b57b2629 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -521,6 +521,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(); @@ -532,6 +533,7 @@ define([ }); $text.on('click', function() { var $picker = $('', { type: 'color', value: textColor }) + .css({ display: 'none', }) .on('change', function() { updateColors(this.value, undefined); onLocal(); From 0a9d34a6c9e4db1ea42261c85315e096ad370cdf Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 24 Oct 2016 15:29:46 +0200 Subject: [PATCH 07/21] 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 9e92a597b32f5fb68d094f7f5feec4e366ed5ec1 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 24 Oct 2016 18:32:43 +0200 Subject: [PATCH 08/21] Ability to edit the title in the toolbar by clicking it --- www/common/cryptpad-common.js | 29 ++++++++++++++++++++++++----- www/common/toolbar.js | 26 +++++++++++++++++++------- www/pad/main.js | 27 +++++++++++++++++---------- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index b6d5f1588..51d1aadf1 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -302,13 +302,17 @@ define([ var type = parsed.type; var untitledIndex = 1; var name = (Messages.type)[type] + ' - ' + new Date().toString().split(' ').slice(0,4).join(' '); - if (isNameAvailable(name, parsed, recentPads)) { return name; } - while (!isNameAvailable(name + ' - ' + untitledIndex, parsed, recentPads)) { untitledIndex++; } - return name + ' - ' + untitledIndex; + return name; + /* + * Pad titles are shared in the document so it does not make sense anymore to avoid duplicates + if (isNameAvailable(name, parsed, recentPads)) { return name; } + while (!isNameAvailable(name + ' - ' + untitledIndex, parsed, recentPads)) { untitledIndex++; } + return name + ' - ' + untitledIndex; + */ }; var isDefaultName = common.isDefaultName = function (parsed, title) { var name = getDefaultName(parsed, []); - return title.slice(0, name.length) === name; + return title === name; }; var makePad = function (href, title) { @@ -622,7 +626,21 @@ define([ var renamePad = common.renamePad = function (title, callback) { if (title === null) { return; } - common.causesNamingConflict(title, function (err, conflicts) { + if (title.trim() === "") { + var parsed = parsePadUrl(window.location.href); + title = getDefaultName(parsed); + } + + common.setPadTitle(title, function (err, data) { + if (err) { + console.log("unable to set pad title"); + console.log(err); + return; + } + callback(null, title); + }); + /* Pad titles are shared in the document. We don't check for duplicates anymore. + common.causesNamingConflict(title, function (err, conflicts) { if (err) { console.log("Unable to determine if name caused a conflict"); console.error(err); @@ -644,6 +662,7 @@ define([ callback(null, title); }); }); + */ }; var createButton = common.createButton = function (type, rightside, data, callback) { var button; diff --git a/www/common/toolbar.js b/www/common/toolbar.js index bd58f324a..28e218046 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -303,29 +303,40 @@ define([ $(lagElement).append(lagLight); }; - var createTitle = function ($container, readOnly, cb) { + var createTitle = function ($container, readOnly, config, Cryptpad) { + var callback = config.onRename; + var placeholder = config.defaultName; + var $titleContainer = $('', { id: 'toolbarTitle', 'class': TITLE_CLS }).appendTo($container); var $text = $('').appendTo($titleContainer); - if (readOnly === 1) { return; } + if (readOnly === 1 || typeof(Cryptpad) === "unedfined") { return; } var $input = $('', { - type: 'text' + type: 'text', + placeholder: placeholder }).appendTo($titleContainer).hide(); + $input.on('mousedown', function (e) { + if (!$input.is(":focus")) { + $input.focus(); + } + e.stopPropagation(); + return true; + }); $input.on('keyup', function (e) { if (e.which === 13) { - Cryptpad.renamePad(title, function (err, newtitle) { + var name = $input.val().trim(); + Cryptpad.renamePad($input.val(), function (err, newtitle) { if (err) { return; } $text.text(newtitle); - cb(null, newtitle); + callback(null, newtitle); $input.hide(); $text.show(); }); } }); $text.on('click', function () { - console.log('click'); $text.hide(); $input.val($text.text()); $input.show(); @@ -335,12 +346,13 @@ define([ var create = Bar.create = function ($container, myUserName, realtime, getLag, userList, config) { var readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1; + var Cryptpad = config.common; var toolbar = createRealtimeToolbar($container); 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 $titleElement = createTitle(toolbar.find('.' + TOP_CLS), readOnly, config.title, Cryptpad); 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 d6f3fdef5..14f00ced0 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -86,6 +86,8 @@ define([ editor.on('instanceReady', function (Ckeditor) { var $bar = $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox'); + var parsedHash = Cryptpad.parsePadUrl(window.location.href); + var defaultName = Cryptpad.getDefaultName(parsedHash); if (readOnly) { $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox > .cke_toolbar').hide(); @@ -318,13 +320,10 @@ define([ }; var suggestName = function () { - var parsed = Cryptpad.parsePadUrl(window.location.href); - var name = Cryptpad.getDefaultName(parsed, []); - - if (Cryptpad.isDefaultName(parsed, document.title)) { - return getHeadingText() || document.title; + if (Cryptpad.isDefaultName(parsedHash, document.title)) { + return getHeadingText() || defaultName; } else { - return document.title || getHeadingText() || name; + return document.title || getHeadingText() || defaultName; } }; @@ -350,6 +349,8 @@ define([ }; if (!isDefaultTitle()) { hjson[3].metadata.title = document.title; + } else { + hjson[3].metadata.title = ""; } return stringify(hjson); }; @@ -396,14 +397,16 @@ define([ // Change the title now, and set it back to the old value if there is an error var oldTitle = document.title; document.title = newTitle; - Cryptpad.setPadTitle(newTitle, function (err, data) { + Cryptpad.renamePad(newTitle, function (err, data) { if (err) { console.log("Couldn't set pad title"); console.error(err); document.title = oldTitle; return; } - $bar.find('.' + Toolbar.constants.title).find('span').text(newTitle); + document.title = data; + $bar.find('.' + Toolbar.constants.title).find('span').text(data); + $bar.find('.' + Toolbar.constants.title).find('input').val(data); }); }; @@ -417,7 +420,7 @@ define([ // Update the local user data addToUserList(userData); } - if (peerMetadata.metadata.title) { + if (typeof peerMetadata.metadata.title !== "undefined") { updateTitle(peerMetadata.metadata.title); } } @@ -526,7 +529,11 @@ define([ userData: userList, readOnly: readOnly, ifrw: ifrw, - onRename: renameCb + title: { + onRename: renameCb, + defaultName: defaultName + }, + common: Cryptpad }; if (readOnly) {delete config.changeNameID; } toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); From 6351d1856f026944e7aef86c27effd628cf74818 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 25 Oct 2016 15:22:35 +0200 Subject: [PATCH 09/21] Remove the top bar and move its content in the applications' toolbars --- customize.dist/DecorateToolbar.js | 5 + customize.dist/languageSelector.js | 4 +- customize.dist/messages.js | 9 ++ customize.dist/src/toolbar.less | 96 +++++++++++++++--- customize.dist/toolbar.css | 110 +++++++++++++++++---- customize.dist/translations/messages.fr.js | 2 + customize.dist/translations/messages.js | 2 + www/code/index.html | 2 +- www/code/main.js | 59 ++++++----- www/common/toolbar.js | 86 ++++++++++++++-- www/pad/index.html | 2 +- www/pad/main.js | 9 +- www/slide/index.html | 2 +- www/slide/main.js | 59 ++++++----- 14 files changed, 344 insertions(+), 103 deletions(-) diff --git a/customize.dist/DecorateToolbar.js b/customize.dist/DecorateToolbar.js index d6f77ea30..6ec6eac89 100644 --- a/customize.dist/DecorateToolbar.js +++ b/customize.dist/DecorateToolbar.js @@ -10,6 +10,11 @@ define([ var main = function () { var url = window.location.pathname; var isHtml = /\.html/.test(url) || url === '/' || url === ''; + var isPoll = /\/poll\//.test(url); + if (!isHtml && !isPoll) { + Messages._applyTranslation(); + return; + } $.ajax({ url: isHtml ? '/customize/BottomBar.html' : '/customize/Header.html', success: function (ret) { diff --git a/customize.dist/languageSelector.js b/customize.dist/languageSelector.js index af949a813..f857680b3 100644 --- a/customize.dist/languageSelector.js +++ b/customize.dist/languageSelector.js @@ -20,8 +20,8 @@ define(['/bower_components/jquery/dist/jquery.min.js'], function() { return getStoredLanguage() || getBrowserLanguage(); }; - var main = out.main = function () { - var selector = $('#language-selector'); + var main = out.main = function ($select) { + var selector = $select || $('#language-selector'); if (!selector.length) { return; } // Select the current language in the list diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 1801fc84d..a1ff01d8e 100644 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -22,6 +22,15 @@ define(['/customize/languageSelector.js', messages = $.extend(true, {}, Default, map[language]); } + messages._languages = { + 'en': Default._languageName + } + for (var l in map) { + messages._languages[l] = map[l]._languageName || l; + } + + messages._initSelector = LS.main; + // Get keys with parameters messages._getKey = function (key, argArray) { if (!messages[key]) { return '?'; } diff --git a/customize.dist/src/toolbar.less b/customize.dist/src/toolbar.less index 9832fc0a9..a674db185 100644 --- a/customize.dist/src/toolbar.less +++ b/customize.dist/src/toolbar.less @@ -39,7 +39,7 @@ } } - button, .rightside-element { + button, select, .rightside-element { height: 26px; padding-right: 5px; padding-left: 5px; @@ -108,30 +108,94 @@ .cryptpad-toolbar-top { display: block; text-align: center; + height: 3em; + position: relative; + margin-bottom: 3px; + @media screen and (max-width: 400px) { + height: 6em; + } .cryptpad-title { - text-align: center; + span { + font-size: 1.5em; + vertical-align: middle; + line-height: 2em; + &:hover { + border: 1px solid #888; + border-radius: 2px; + background: white; + padding: 5px; + } + } input { + font-size: 1.5em; + vertical-align: middle; + height: 100%; + box-sizing: border-box; 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; + padding: 0px 5px; + } + } + .cryptpad-link { + position: absolute; + left: 0px; + height: 3em; + @media screen and (max-width: 400px) { + top: 3em; + } + @media screen and (min-width: 401px) { + top: 0px; + } + + a.cryptpad-logo { + cursor: pointer; + height: 3em; + border: 1px solid #aaa; + border-radius: @border-radius; + padding: 0px 5px; + text-decoration: none; + color: inherit; + img { + vertical-align: middle; + height: 3em; + cursor: pointer; + } + span { + font-size: 1.5em; + margin-left: 5px; + vertical-align: middle; + cursor: pointer; + } + } + .big { + @media screen and (max-width: 400px) { + display: none; + } + @media screen and (min-width: 401px) { + display: inline-block; + } + } + .small { + @media screen and (max-width: 400px) { + display: inline-block; + } + @media screen and (min-width: 401px) { + display: none; } } } + .cryptpad-user { + position: absolute; + right: 0; + @media screen and (max-width: 400px) { + top: 3em; + } + @media screen and (min-width: 401px) { + top: 0px; + } + } } .cryptpad-toolbar-leftside { float: left; diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index 9cbde4f5d..5bf1dc0bf 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -38,6 +38,7 @@ margin: 2px 0px 2px 4px; } .cryptpad-toolbar button, +.cryptpad-toolbar select, .cryptpad-toolbar .rightside-element { height: 26px; padding-right: 5px; @@ -104,30 +105,105 @@ .cryptpad-toolbar-top { display: block; text-align: center; + height: 3em; + position: relative; + margin-bottom: 3px; } -.cryptpad-toolbar-top .cryptpad-title { - text-align: center; +@media screen and (max-width: 400px) { + .cryptpad-toolbar-top { + height: 6em; + } +} +.cryptpad-toolbar-top .cryptpad-title span { + font-size: 1.5em; + vertical-align: middle; + line-height: 2em; +} +.cryptpad-toolbar-top .cryptpad-title span:hover { + border: 1px solid #888; + border-radius: 2px; + background: white; + padding: 5px; } .cryptpad-toolbar-top .cryptpad-title input { + font-size: 1.5em; + vertical-align: middle; + height: 100%; + box-sizing: border-box; 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; + padding: 0px 5px; +} +.cryptpad-toolbar-top .cryptpad-link { + position: absolute; + left: 0px; + height: 3em; +} +@media screen and (max-width: 400px) { + .cryptpad-toolbar-top .cryptpad-link { + top: 3em; + } +} +@media screen and (min-width: 401px) { + .cryptpad-toolbar-top .cryptpad-link { + top: 0px; + } +} +.cryptpad-toolbar-top .cryptpad-link a.cryptpad-logo { + cursor: pointer; + height: 3em; + border: 1px solid #aaa; + border-radius: 1px; + padding: 0px 5px; + text-decoration: none; + color: inherit; +} +.cryptpad-toolbar-top .cryptpad-link a.cryptpad-logo img { + vertical-align: middle; + height: 3em; + cursor: pointer; +} +.cryptpad-toolbar-top .cryptpad-link a.cryptpad-logo span { + font-size: 1.5em; + margin-left: 5px; + vertical-align: middle; + cursor: pointer; +} +@media screen and (max-width: 400px) { + .cryptpad-toolbar-top .cryptpad-link .big { + display: none; + } +} +@media screen and (min-width: 401px) { + .cryptpad-toolbar-top .cryptpad-link .big { + display: inline-block; + } +} +@media screen and (max-width: 400px) { + .cryptpad-toolbar-top .cryptpad-link .small { + display: inline-block; + } +} +@media screen and (min-width: 401px) { + .cryptpad-toolbar-top .cryptpad-link .small { + display: none; + } +} +.cryptpad-toolbar-top .cryptpad-user { + position: absolute; + right: 0; +} +@media screen and (max-width: 400px) { + .cryptpad-toolbar-top .cryptpad-user { + top: 3em; + } +} +@media screen and (min-width: 401px) { + .cryptpad-toolbar-top .cryptpad-user { + top: 0px; + } } .cryptpad-toolbar-leftside { float: left; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 57f50a33a..49faa6f2e 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -1,6 +1,8 @@ define(function () { var out = {}; + out._languageName = "Français"; + out.main_title = "Cryptpad: Editeur collaboratif en temps réel, zero knowledge"; out.type = {}; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 51c8f73a7..1821cde81 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -1,6 +1,8 @@ define(function () { var out = {}; + out._languageName = 'English'; + out.main_title = "Cryptpad: Zero Knowledge, Collaborative Real Time Editing"; out.type = {}; diff --git a/www/code/index.html b/www/code/index.html index bdef6b6f4..9b7c92d88 100644 --- a/www/code/index.html +++ b/www/code/index.html @@ -21,7 +21,7 @@ } #iframe-container { position: fixed; - top: 2.6em; + top: 0px; bottom: 0px; right: 0px; left: 0px; diff --git a/www/code/main.js b/www/code/main.js index 586910ac0..77ecd84be 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -45,10 +45,13 @@ define([ var andThen = function (CMeditor) { var CodeMirror = module.CodeMirror = CMeditor; CodeMirror.modeURL = "/bower_components/codemirror/mode/%N/%N.js"; - var $pad = $('#pad-iframe'); var $textarea = $pad.contents().find('#editor1'); + var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); + var parsedHash = Cryptpad.parsePadUrl(window.location.href); + var defaultName = Cryptpad.getDefaultName(parsedHash); + var editor = module.editor = CMeditor.fromTextArea($textarea[0], { lineNumbers: true, lineWrapping: true, @@ -176,6 +179,9 @@ define([ if (!isDefaultTitle()) { obj.metadata.title = document.title; } + else { + obj.metadata.title = ""; + } // set mode too... obj.highlightMode = module.highlightMode; @@ -256,13 +262,10 @@ define([ }; var suggestName = function () { - var parsed = Cryptpad.parsePadUrl(window.location.href); - var name = Cryptpad.getDefaultName(parsed, []); - - if (Cryptpad.isDefaultName(parsed, document.title)) { - return getHeadingText() || document.title; + if (Cryptpad.isDefaultName(parsedHash, document.title)) { + return getHeadingText() || defaultName; } else { - return document.title || getHeadingText() || name; + return document.title || getHeadingText() || defaultName; } }; @@ -308,13 +311,23 @@ define([ onLocal(); }; + var renameCb = function (err, title) { + if (err) { return; } + document.title = title; + onLocal(); + }; + var onInit = config.onInit = function (info) { - var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); toolbarList = info.userList; var config = { userData: userList, readOnly: readOnly, - ifrw: ifrw + ifrw: ifrw, + title: { + onRename: renameCb, + defaultName: defaultName + }, + common: Cryptpad }; if (readOnly) {delete config.changeNameID; } toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); @@ -336,8 +349,8 @@ define([ /* add a "change username" button */ getLastName(function (err, lastName) { userNameButtonObject.lastName = lastName; - var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName); - $userBlock.append($username).hide(); + var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName).hide(); + $userBlock.append($username); }); /* add an export button */ @@ -350,11 +363,6 @@ define([ $rightside.append($import); /* add a rename button */ - var renameCb = function (err, title) { - if (err) { return; } - document.title = title; - onLocal(); - }; var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb); $rightside.append($setTitle); } @@ -454,14 +462,7 @@ define([ console.error(err); return; } - document.title = title || info.channel.slice(0, 8); - Cryptpad.setPadTitle(title, function (err, data) { - if (err) { - console.log("Unable to set pad title"); - console.error(err); - return; - } - }); + updateTitle(title || defaultName); }); }; @@ -470,13 +471,16 @@ define([ // Change the title now, and set it back to the old value if there is an error var oldTitle = document.title; document.title = newTitle; - Cryptpad.setPadTitle(newTitle, function (err, data) { + Cryptpad.renamePad(newTitle, function (err, data) { if (err) { console.log("Couldn't set pad title"); console.error(err); document.title = oldTitle; return; } + document.title = data; + $bar.find('.' + Toolbar.constants.title).find('span').text(data); + $bar.find('.' + Toolbar.constants.title).find('input').val(data); }); }; @@ -489,7 +493,7 @@ define([ // Update the local user data addToUserList(userData); } - if (json.metadata.title) { + if (typeof json.metadata.title !== "undefined") { updateTitle(json.metadata.title); } } @@ -652,6 +656,9 @@ define([ if (!isDefaultTitle()) { hjson2.metadata.title = document.title; } + else { + hjson2.metadata.title = ""; + } var shjson2 = stringify(hjson2); if (shjson2 !== shjson) { console.error("shjson2 !== shjson"); diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 28e218046..117c07dcc 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -36,6 +36,7 @@ define([ 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"; + var USER_CLS = Bar.constants.userAdmin = "cryptpad-user"; /** Key in the localStore which indicates realtime activity should be disallowed. */ // TODO remove? will never be used in cryptpad @@ -195,7 +196,7 @@ define([ if (n === 1) { return '; + ' + Messages.oneViewer; } return '; + ' + Messages._getKey('viewers', [n]); }; - var updateUserList = function (myUserName, userlistElement, userList, userData, readOnly, $stateElement) { + var updateUserList = function (myUserName, userlistElement, userList, userData, readOnly, $stateElement, $userAdminElement) { var meIdx = userList.indexOf(myUserName); if (meIdx === -1) { $stateElement.text(Messages.synchronizing); @@ -206,7 +207,7 @@ define([ // Make sure the user block elements are displayed var $userButtons = $(userlistElement).find("#userButtons"); $userButtons.show(); - var $userElement = $(userlistElement).find('.' + USERNAME_CLS); + var $userElement = $userAdminElement.find('.' + USERNAME_CLS); $userElement.show(); var numberOfUsers = userList.length; @@ -261,7 +262,7 @@ define([ if (!name) { name = Messages.anonymous; } - $userElement.find("button").html(icon + ' ' + name); + $userElement.find("button").html(icon + ' ' + name).show(); } }; @@ -303,7 +304,60 @@ define([ $(lagElement).append(lagLight); }; + var createLinkToMain = function ($topContainer) { + var $linkContainer = $('', { + 'class': "cryptpad-link" + }).appendTo($topContainer); + var $imgTag = $('', { + src: "/customize/cryptofist_mini.png", + alt: "Cryptpad", + 'class': "cryptofist" + }); + var $aTagSmall = $('', { + href: "/", + title: Messages.header_logoTitle, + 'class': "cryptpad-logo" + }).append($imgTag); + $span = $('').text('CryptPad'); + var $aTagBig = $aTagSmall.clone().addClass('big').append($span); + $aTagSmall.addClass('small'); + + $linkContainer.append($aTagSmall).append($aTagBig); + }; + + var createUserAdmin = function ($topContainer) { + var $userContainer = $('', { + 'class': USER_CLS + }).appendTo($topContainer); + + var $span = $('' , { + 'class': 'cryptpad-language' + }); + var $select = $('', { type: 'text', placeholder: placeholder @@ -335,6 +391,10 @@ define([ $text.show(); }); } + else if (e.which === 27) { + $input.hide(); + $text.show(); + } }); $text.on('click', function () { $text.hide(); @@ -342,9 +402,11 @@ define([ $input.show(); $input.focus(); }); + return $titleContainer; }; var create = Bar.create = function ($container, myUserName, realtime, getLag, userList, config) { + config = config || {}; var readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1; var Cryptpad = config.common; @@ -353,6 +415,8 @@ define([ var spinner = createSpinner(toolbar.find('.' + RIGHTSIDE_CLS)); var lagElement = createLagElement(toolbar.find('.' + RIGHTSIDE_CLS)); var $titleElement = createTitle(toolbar.find('.' + TOP_CLS), readOnly, config.title, Cryptpad); + var $linkElement = createLinkToMain(toolbar.find('.' + TOP_CLS)); + var $userAdminElement = createUserAdmin(toolbar.find('.' + TOP_CLS)); var userData = config.userData; // readOnly = 1 (readOnly enabled), 0 (disabled), -1 (old pad without readOnly mode) var saveElement; @@ -368,7 +432,15 @@ define([ } $container.find('.cryptpad-dropdown').hide(); }; - $(config.ifrw).on('click',removeDropdowns); + var cancelEditTitle = function (e) { + if ($(e.target).parents('.' + TITLE_CLS).length) { + return; + } + $titleElement.find('input').hide(); + $titleElement.find('span').show(); + }; + $(config.ifrw).on('click', removeDropdowns); + $(config.ifrw).on('click', cancelEditTitle); if (config.ifrw.$('iframe').length) { var innerIfrw = config.ifrw.$('iframe').each(function (i, el) { $(el.contentWindow).on('click', removeDropdowns); @@ -383,7 +455,7 @@ define([ if(newUserData) { // Someone has changed his name/color userData = newUserData; } - updateUserList(myUserName, userListElement, users, userData, readOnly, $stateElement); + updateUserList(myUserName, userListElement, users, userData, readOnly, $stateElement, $userAdminElement); }; var ks = function () { diff --git a/www/pad/index.html b/www/pad/index.html index 2bab2dee9..13f0d2938 100644 --- a/www/pad/index.html +++ b/www/pad/index.html @@ -21,7 +21,7 @@ } #pad-iframe { position:fixed; - top:2.5em; + top:0px; left:0px; bottom:0px; right:0px; diff --git a/www/pad/main.js b/www/pad/main.js index 689d70e86..0ca608b21 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -253,7 +253,7 @@ define([ }; var initializing = true; - var userList = module.userList = {}; // List of pretty name of all users (mapped with their server ID) + var userList = module.userList = {}; // List of pretty names for all users (mapped with their ID) var toolbarList; // List of users still connected to the channel (server IDs) var addToUserList = function(data) { var users = module.users; @@ -556,8 +556,8 @@ define([ /* add a "change username" button */ getLastName(function (err, lastName) { userNameButtonObject.lastName = lastName; - var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName); - $userBlock.append($username).hide(); + var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName).hide(); + $userBlock.append($username); }); /* add an export button */ @@ -604,8 +604,7 @@ define([ console.log("Couldn't get pad title"); return; } - updateTitle(title || info.channel.slice(0, 8)); - document.title = title || info.channel.slice(0, 8); + updateTitle(title || defaultName); }); }; diff --git a/www/slide/index.html b/www/slide/index.html index b36464b0e..f08782eb2 100644 --- a/www/slide/index.html +++ b/www/slide/index.html @@ -21,7 +21,7 @@ } #iframe-container { position: fixed; - top: 2.6em; + top: 0px; bottom: 0px; right: 0px; left: 0px; diff --git a/www/slide/main.js b/www/slide/main.js index a5c41633a..3e48d745a 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -62,10 +62,13 @@ define([ var andThen = function (CMeditor) { var CodeMirror = module.CodeMirror = CMeditor; CodeMirror.modeURL = "/bower_components/codemirror/mode/%N/%N.js"; - var $pad = $('#pad-iframe'); var $textarea = $pad.contents().find('#editor1'); + var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); + var parsedHash = Cryptpad.parsePadUrl(window.location.href); + var defaultName = Cryptpad.getDefaultName(parsedHash); + var editor = module.editor = CMeditor.fromTextArea($textarea[0], { lineNumbers: true, lineWrapping: true, @@ -211,6 +214,9 @@ define([ if (!isDefaultTitle()) { obj.metadata.title = APP.title; } + else { + obj.metadata.title = ""; + } if (textColor) { obj.metadata.color = textColor; } @@ -286,13 +292,10 @@ define([ }; var suggestName = function () { - var parsed = Cryptpad.parsePadUrl(window.location.href); - var name = Cryptpad.getDefaultName(parsed, []); - - if (Cryptpad.isDefaultName(parsed, APP.title)) { - return getHeadingText() || APP.title; + if (Cryptpad.isDefaultName(parsedHash, APP.title)) { + return getHeadingText() || defaultName; } else { - return APP.title || getHeadingText() || name; + return APP.title || getHeadingText() || defaultName; } }; @@ -344,7 +347,7 @@ define([ var oldTitle = APP.title; APP.title = newTitle; setTabTitle(); - Cryptpad.setPadTitle(newTitle, function (err, data) { + Cryptpad.renamePad(newTitle, function (err, data) { if (err) { console.log("Couldn't set pad title"); console.error(err); @@ -352,6 +355,10 @@ define([ setTabTitle(); return; } + APP.title = data; + setTabTitle(); + $bar.find('.' + Toolbar.constants.title).find('span').text(data); + $bar.find('.' + Toolbar.constants.title).find('input').val(data); }); }; @@ -378,20 +385,31 @@ define([ // Update the local user data addToUserList(userData); } - if (json.metadata.title) { + if (typeof json.metadata.title !== "undefined") { updateTitle(json.metadata.title); } updateColors(json.metadata.color, json.metadata.backColor); } }; + var renameCb = function (err, title) { + if (err) { return; } + APP.title = title; + setTabTitle(); + onLocal(); + }; + var onInit = config.onInit = function (info) { - var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); toolbarList = info.userList; var config = { userData: userList, readOnly: readOnly, - ifrw: $('#pad-iframe')[0].contentWindow + ifrw: ifrw, + title: { + onRename: renameCb, + defaultName: defaultName + }, + common: Cryptpad }; if (readOnly) {delete config.changeNameID; } toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); @@ -413,8 +431,8 @@ define([ /* add a "change username" button */ getLastName(function (err, lastName) { userNameButtonObject.lastName = lastName; - var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName); - $userBlock.append($username).hide(); + var $username = module.$userNameButton = Cryptpad.createButton('username', false, userNameButtonObject, setName).hide(); + $userBlock.append($username); }); /* add an export button */ @@ -427,12 +445,6 @@ define([ $rightside.append($import); /* add a rename button */ - var renameCb = function (err, title) { - if (err) { return; } - APP.title = title; - setTabTitle(); - onLocal(); - }; var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb); $rightside.append($setTitle); } @@ -576,14 +588,7 @@ define([ console.error(err); return; } - document.title = APP.title = title || info.channel.slice(0, 8); - Cryptpad.setPadTitle(title, function (err, data) { - if (err) { - console.log("Unable to set pad title"); - console.error(err); - return; - } - }); + updateTitle(title || defaultName); }); }; From 87d86384ac7e63b766e2aadd3f6fe8079718e707 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 25 Oct 2016 17:29:13 +0200 Subject: [PATCH 10/21] Fix broken elements in the new toolbar --- customize.dist/messages.js | 4 +- customize.dist/src/toolbar.less | 7 +- customize.dist/toolbar.css | 5 +- customize.dist/translations/messages.fr.js | 1 + customize.dist/translations/messages.js | 5 +- www/code/main.js | 136 ++++++++++----------- www/common/toolbar.js | 23 +++- www/pad/main.js | 22 ++-- www/slide/main.js | 25 ++-- 9 files changed, 129 insertions(+), 99 deletions(-) diff --git a/customize.dist/messages.js b/customize.dist/messages.js index a1ff01d8e..f1062ada3 100644 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -22,9 +22,11 @@ define(['/customize/languageSelector.js', messages = $.extend(true, {}, Default, map[language]); } + // messages_languages return the available translations and their name in an object : + // { "en": "English", "fr": "French", ... } messages._languages = { 'en': Default._languageName - } + }; for (var l in map) { messages._languages[l] = map[l]._languageName || l; } diff --git a/customize.dist/src/toolbar.less b/customize.dist/src/toolbar.less index a674db185..ab517124f 100644 --- a/customize.dist/src/toolbar.less +++ b/customize.dist/src/toolbar.less @@ -152,11 +152,14 @@ a.cryptpad-logo { cursor: pointer; height: 3em; - border: 1px solid #aaa; - border-radius: @border-radius; padding: 0px 5px; text-decoration: none; color: inherit; + &:hover { + span { + text-decoration: underline; + } + } img { vertical-align: middle; height: 3em; diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index 5bf1dc0bf..39b060844 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -154,12 +154,13 @@ .cryptpad-toolbar-top .cryptpad-link a.cryptpad-logo { cursor: pointer; height: 3em; - border: 1px solid #aaa; - border-radius: 1px; padding: 0px 5px; text-decoration: none; color: inherit; } +.cryptpad-toolbar-top .cryptpad-link a.cryptpad-logo:hover span { + text-decoration: underline; +} .cryptpad-toolbar-top .cryptpad-link a.cryptpad-logo img { vertical-align: middle; height: 3em; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 49faa6f2e..299bcd5b3 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -53,6 +53,7 @@ define(function () { out.renameButtonTitle = 'Changer le titre utilisé par ce document dans la page d\'accueil de Cryptpad'; out.renamePrompt = 'Quel titre souhaitez-vous utiliser pour ce document ?'; out.renameConflict = 'Un autre document existe déjà avec le même titre'; + out.clickToEdit = 'Cliquer pour modifier'; out.forgetButton = 'OUBLIER'; out.forgetButtonTitle = 'Enlever ce document de la liste en page d\'accueil'; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 1821cde81..69cb4a4e7 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -53,6 +53,7 @@ define(function () { out.renameButtonTitle = 'Change the title under which this document is listed on your home page'; out.renamePrompt = 'How would you like to title this pad?'; out.renameConflict = 'Another pad already has that title'; + out.clickToEdit = "Click to edit"; out.forgetButton = 'FORGET'; out.forgetButtonTitle = 'Remove this document from your home page listings'; @@ -81,8 +82,8 @@ define(function () { out.readonlyUrl = 'Read only document'; out.copyReadOnly = "Copy URL to clipboard"; out.openReadOnly = "Open in a new tab"; - out.editing = "editing"; - out.viewing = "viewing"; + out.editing = "editor(s)"; + out.viewing = "viewer(s)"; out.editShare = "Share"; out.editShareTitle = "Copy the edit URL to clipboard"; out.viewShare = "Share view URL"; diff --git a/www/code/main.js b/www/code/main.js index 77ecd84be..f2db83352 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -164,30 +164,30 @@ define([ var initializing = true; + var stringifyInner = function (textValue) { + var obj = { + content: textValue, + metadata: { + users: userList, + defaultTitle: defaultName + } + }; + obj.metadata.title = document.title; + // set mode too... + obj.highlightMode = module.highlightMode; + + // stringify the json and send it into chainpad + return stringify(obj); + }; + var onLocal = config.onLocal = function () { if (initializing) { return; } if (readOnly) { return; } editor.save(); - var textValue = canonicalize($textarea.val()); - var obj = {content: textValue}; - // append the userlist to the hyperjson structure - obj.metadata = { - users: userList - }; - if (!isDefaultTitle()) { - obj.metadata.title = document.title; - } - else { - obj.metadata.title = ""; - } - - // set mode too... - obj.highlightMode = module.highlightMode; - - // stringify the json and send it into chainpad - var shjson = stringify(obj); + var textValue = canonicalize($textarea.val()); + var shjson = stringifyInner(textValue); module.patchText(shjson); @@ -262,8 +262,8 @@ define([ }; var suggestName = function () { - if (Cryptpad.isDefaultName(parsedHash, document.title)) { - return getHeadingText() || defaultName; + if (document.title === defaultName) { + return getHeadingText() || ""; } else { return document.title || getHeadingText() || defaultName; } @@ -317,7 +317,48 @@ define([ onLocal(); }; - var onInit = config.onInit = function (info) { + var updateTitle = function (newTitle) { + if (newTitle === document.title) { return; } + // Change the title now, and set it back to the old value if there is an error + var oldTitle = document.title; + document.title = newTitle; + Cryptpad.renamePad(newTitle, function (err, data) { + if (err) { + console.log("Couldn't set pad title"); + console.error(err); + document.title = oldTitle; + return; + } + document.title = data; + $bar.find('.' + Toolbar.constants.title).find('span').text(data); + $bar.find('.' + Toolbar.constants.title).find('input').val(data); + }); + }; + + var updateDefaultTitle = function (defaultTitle) { + defaultName = defaultTitle; + $bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); + }; + + var updateMetadata = function(shjson) { + // Extract the user list (metadata) from the hyperjson + var json = (shjson === "") ? "" : JSON.parse(shjson); + if (json && json.metadata) { + if (json.metadata.users) { + var userData = json.metadata.users; + // Update the local user data + addToUserList(userData); + } + if (json.metadata.defaultTitle) { + updateDefaultTitle(json.metadata.defaultTitle); + } + if (typeof json.metadata.title !== "undefined") { + updateTitle(json.metadata.title); + } + } + }; + + var onInit = config.onInit = function (info) { toolbarList = info.userList; var config = { userData: userList, @@ -325,7 +366,8 @@ define([ ifrw: ifrw, title: { onRename: renameCb, - defaultName: defaultName + defaultName: defaultName, + suggestName: suggestName }, common: Cryptpad }; @@ -466,39 +508,6 @@ define([ }); }; - var updateTitle = function (newTitle) { - if (newTitle === document.title) { return; } - // Change the title now, and set it back to the old value if there is an error - var oldTitle = document.title; - document.title = newTitle; - Cryptpad.renamePad(newTitle, function (err, data) { - if (err) { - console.log("Couldn't set pad title"); - console.error(err); - document.title = oldTitle; - return; - } - document.title = data; - $bar.find('.' + Toolbar.constants.title).find('span').text(data); - $bar.find('.' + Toolbar.constants.title).find('input').val(data); - }); - }; - - var updateMetadata = function(shjson) { - // Extract the user list (metadata) from the hyperjson - var json = (shjson === "") ? "" : JSON.parse(shjson); - if (json && json.metadata) { - if (json.metadata.users) { - var userData = json.metadata.users; - // Update the local user data - addToUserList(userData); - } - if (typeof json.metadata.title !== "undefined") { - updateTitle(json.metadata.title); - } - } - }; - var unnotify = module.unnotify = function () { if (module.tabNotification && typeof(module.tabNotification.cancel) === 'function') { @@ -645,21 +654,8 @@ define([ editor.scrollTo(scroll.left, scroll.top); if (!readOnly) { - var localDoc = canonicalize($textarea.val()); - var hjson2 = { - content: localDoc, - metadata: { - users: userList - }, - highlightMode: highlightMode, - }; - if (!isDefaultTitle()) { - hjson2.metadata.title = document.title; - } - else { - hjson2.metadata.title = ""; - } - var shjson2 = stringify(hjson2); + var textValue = canonicalize($textarea.val()); + var shjson2 = stringifyInner(textValue); if (shjson2 !== shjson) { console.error("shjson2 !== shjson"); TextPatcher.log(shjson, TextPatcher.diff(shjson, shjson2)); diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 117c07dcc..e342a9241 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -313,14 +313,23 @@ define([ alt: "Cryptpad", 'class': "cryptofist" }); + + // We need to override the "a" tag action here because it is inside the iframe! var $aTagSmall = $('', { href: "/", title: Messages.header_logoTitle, 'class': "cryptpad-logo" }).append($imgTag); - $span = $('').text('CryptPad'); + var $span = $('').text('CryptPad'); var $aTagBig = $aTagSmall.clone().addClass('big').append($span); $aTagSmall.addClass('small'); + var onClick = function (e) { + e.preventDefault(); + window.location = "/"; + }; + + $aTagBig.click(onClick); + $aTagSmall.click(onClick); $linkContainer.append($aTagSmall).append($aTagBig); }; @@ -360,13 +369,14 @@ define([ config = config || {}; var callback = config.onRename; var placeholder = config.defaultName; + var suggestName = config.suggestName; var $titleContainer = $('', { id: 'toolbarTitle', 'class': TITLE_CLS }).appendTo($container); var $text = $('', { - title: "CLick to edit" //TODO translate + title: Messages.clickToEdit }).appendTo($titleContainer); if (readOnly === 1 || typeof(Cryptpad) === "undefined") { return; } var $input = $('', { @@ -383,7 +393,10 @@ define([ $input.on('keyup', function (e) { if (e.which === 13) { var name = $input.val().trim(); - Cryptpad.renamePad($input.val(), function (err, newtitle) { + if (name === "") { + name = $input.attr('placeholder'); + } + Cryptpad.renamePad(name, function (err, newtitle) { if (err) { return; } $text.text(newtitle); callback(null, newtitle); @@ -398,7 +411,8 @@ define([ }); $text.on('click', function () { $text.hide(); - $input.val($text.text()); + var inputVal = suggestName() || ""; + $input.val(inputVal); $input.show(); $input.focus(); }); @@ -444,6 +458,7 @@ define([ if (config.ifrw.$('iframe').length) { var innerIfrw = config.ifrw.$('iframe').each(function (i, el) { $(el.contentWindow).on('click', removeDropdowns); + $(el.contentWindow).on('click', cancelEditTitle); }); } } diff --git a/www/pad/main.js b/www/pad/main.js index 0ca608b21..bfe74e7b6 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -321,8 +321,8 @@ define([ }; var suggestName = function () { - if (Cryptpad.isDefaultName(parsedHash, document.title)) { - return getHeadingText() || defaultName; + if (document.title === defaultName) { + return getHeadingText() || ""; } else { return document.title || getHeadingText() || defaultName; } @@ -346,13 +346,10 @@ define([ hjson[3] = { metadata: { users: userList, + defaultTitle: defaultName } }; - if (!isDefaultTitle()) { - hjson[3].metadata.title = document.title; - } else { - hjson[3].metadata.title = ""; - } + hjson[3].metadata.title = document.title; return stringify(hjson); }; @@ -411,6 +408,11 @@ define([ }); }; + var updateDefaultTitle = function (defaultTitle) { + defaultName = defaultTitle; + $bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); + }; + var updateMetadata = function(shjson) { // Extract the user list (metadata) from the hyperjson var hjson = JSON.parse(shjson); @@ -421,6 +423,9 @@ define([ // Update the local user data addToUserList(userData); } + if (peerMetadata.metadata.defaultTitle) { + updateDefaultTitle(peerMetadata.metadata.defaultTitle); + } if (typeof peerMetadata.metadata.title !== "undefined") { updateTitle(peerMetadata.metadata.title); } @@ -532,7 +537,8 @@ define([ ifrw: ifrw, title: { onRename: renameCb, - defaultName: defaultName + defaultName: defaultName, + suggestName: suggestName }, common: Cryptpad }; diff --git a/www/slide/main.js b/www/slide/main.js index 3e48d745a..31a09a1a6 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -208,15 +208,11 @@ define([ var obj = { content: textValue, metadata: { - users: userList + users: userList, + defaultTitle: defaultName } }; - if (!isDefaultTitle()) { - obj.metadata.title = APP.title; - } - else { - obj.metadata.title = ""; - } + obj.metadata.title = APP.title; if (textColor) { obj.metadata.color = textColor; } @@ -292,8 +288,8 @@ define([ }; var suggestName = function () { - if (Cryptpad.isDefaultName(parsedHash, APP.title)) { - return getHeadingText() || defaultName; + if (APP.title === defaultName) { + return getHeadingText() || ""; } else { return APP.title || getHeadingText() || defaultName; } @@ -376,6 +372,11 @@ define([ } }; + var updateDefaultTitle = function (defaultTitle) { + defaultName = defaultTitle; + $bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); + }; + var updateMetadata = function(shjson) { // Extract the user list (metadata) from the hyperjson var json = (shjson === "") ? "" : JSON.parse(shjson); @@ -385,6 +386,9 @@ define([ // Update the local user data addToUserList(userData); } + if (json.metadata.defaultTitle) { + updateDefaultTitle(json.metadata.defaultTitle); + } if (typeof json.metadata.title !== "undefined") { updateTitle(json.metadata.title); } @@ -407,7 +411,8 @@ define([ ifrw: ifrw, title: { onRename: renameCb, - defaultName: defaultName + defaultName: defaultName, + suggestName: suggestName }, common: Cryptpad }; From 54a63267cd2dae49db636de4ea245a1c25018d0e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 25 Oct 2016 18:34:23 +0200 Subject: [PATCH 11/21] Add a share button and merge the viewers and editors buttons --- customize.dist/src/toolbar.less | 10 ++-- customize.dist/toolbar.css | 10 ++-- www/code/main.js | 4 +- www/common/toolbar.js | 100 ++++++++++++++++++-------------- www/pad/main.js | 4 +- www/slide/main.js | 4 +- 6 files changed, 73 insertions(+), 59 deletions(-) diff --git a/customize.dist/src/toolbar.less b/customize.dist/src/toolbar.less index ab517124f..b997ca9e9 100644 --- a/customize.dist/src/toolbar.less +++ b/customize.dist/src/toolbar.less @@ -33,9 +33,9 @@ color: #000; } &.cryptpad-lag { - float: right; + float: left; line-height: 26px; - margin: 2px 0px 2px 4px; + margin: 2px 0px; } } @@ -203,6 +203,9 @@ .cryptpad-toolbar-leftside { float: left; margin-bottom: -1px; + .cryptpad-user-list { + float: right; + } .cryptpad-dropdown-container { position: relative; display: inline-block; @@ -255,7 +258,6 @@ } .cryptpad-toolbar-rightside { text-align: right; - margin-right: 30px; //float: right; } .cryptpad-spinner { @@ -267,7 +269,7 @@ font-size: 20px; } .cryptpad-readonly { - margin-right: 20px; + margin-right: 5px; font-weight: bold; text-transform: uppercase; } diff --git a/customize.dist/toolbar.css b/customize.dist/toolbar.css index 39b060844..4f441169b 100644 --- a/customize.dist/toolbar.css +++ b/customize.dist/toolbar.css @@ -33,9 +33,9 @@ color: #000; } .cryptpad-toolbar div.cryptpad-lag { - float: right; + float: left; line-height: 26px; - margin: 2px 0px 2px 4px; + margin: 2px 0px; } .cryptpad-toolbar button, .cryptpad-toolbar select, @@ -210,6 +210,9 @@ float: left; margin-bottom: -1px; } +.cryptpad-toolbar-leftside .cryptpad-user-list { + float: right; +} .cryptpad-toolbar-leftside .cryptpad-dropdown-container { position: relative; display: inline-block; @@ -261,7 +264,6 @@ } .cryptpad-toolbar-rightside { text-align: right; - margin-right: 30px; } .cryptpad-spinner { float: left; @@ -272,7 +274,7 @@ font-size: 20px; } .cryptpad-readonly { - margin-right: 20px; + margin-right: 5px; font-weight: bold; text-transform: uppercase; } diff --git a/www/code/main.js b/www/code/main.js index f2db83352..0483c1bf6 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -405,8 +405,8 @@ define([ $rightside.append($import); /* add a rename button */ - var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb); - $rightside.append($setTitle); + //var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb); + //$rightside.append($setTitle); } /* add a forget button */ diff --git a/www/common/toolbar.js b/www/common/toolbar.js index e342a9241..26ade0842 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -52,6 +52,7 @@ define([ var $style; var firstConnection = true; + var lagErrors = 0; var styleToolbar = function ($container, href) { href = href || '/customize/toolbar.css'; @@ -108,29 +109,31 @@ define([ 'class': 'userlist dropbtn edit', }); var $editIconSmall = $editIcon.clone().addClass('small'); - var $viewIcon = $('