diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index faff1ac35..0b32886cd 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -129,7 +129,9 @@ define(function () { out.saveTemplatePrompt = "Choisir un titre pour ce modèle"; out.templateSaved = "Modèle enregistré !"; out.selectTemplate = "Sélectionner un modèle ou appuyer sur Échap"; - out.useTemplate = "Vous posséder des modèles pour ce type de pad, souhaitez-vous en utiliser un?"; + out.useTemplate = "Commencer avec un modèle?"; + out.useTemplateOK = 'Choisir un modèle (Entrée)'; + out.useTemplateCancel = 'Document vierge (Échap)'; out.previewButtonTitle = "Afficher ou cacher la prévisualisation de Markdown"; diff --git a/readme.md b/readme.md index ae3c9e144..956077d15 100644 --- a/readme.md +++ b/readme.md @@ -20,6 +20,10 @@ It also contains information on keeping your instance of CryptPad up to date. See [Cryptpad-Docker](docs/cryptpad-docker.md) +## Setup using Ansible + +See [Ansible Role for Cryptpad](https://github.com/systemli/ansible-role-cryptpad) + # Security CryptPad is *private*, not *anonymous*. Privacy protects your data, anonymity protects you. diff --git a/www/common/common-interface.js b/www/common/common-interface.js index b93e57de3..467cad4ab 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -36,8 +36,9 @@ define([ return $('button.ok').last(); }; - var listenForKeys = UI.listenForKeys = function (yes, no) { + var listenForKeys = UI.listenForKeys = function (yes, no, el) { var handler = function (e) { + e.stopPropagation(); switch (e.which) { case 27: // cancel if (typeof(no) === 'function') { no(e); } @@ -48,7 +49,7 @@ define([ } }; - $(window).keyup(handler); + $(el || window).keydown(handler); return handler; }; @@ -114,7 +115,9 @@ define([ }; dialog.frame = function (content) { - return h('div.alertify', [ + return h('div.alertify', { + tabindex: 1, + }, [ h('div.dialog', [ h('div', content), ]) @@ -229,6 +232,7 @@ define([ var close = Util.once(function () { $(frame).fadeOut(150, function () { $(this).remove(); }); stopListening(listener); + cb(); }); listener = listenForKeys(close, close); var $ok = $(ok).click(close); @@ -237,7 +241,6 @@ define([ setTimeout(function () { $ok.focus(); UI.notify(); - if (!document.hasFocus()) { window.focus(); } }); }; @@ -283,7 +286,6 @@ define([ setTimeout(function () { input.select().focus(); UI.notify(); - if (!document.hasFocus()) { window.focus(); } }); }; @@ -330,10 +332,10 @@ define([ document.body.appendChild(frame); setTimeout(function () { UI.notify(); + $(frame).find('.ok').focus(); if (typeof(opt.done) === 'function') { opt.done($ok.closest('.dialog')); } - if (!document.hasFocus()) { window.focus(); } }); }; diff --git a/www/common/userObject.js b/www/common/userObject.js index 504addb15..79d5dc3f0 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -654,10 +654,8 @@ define([ if (workgroup || (!Cryptpad.isLoggedIn() && !config.testMode)) { return; } var filesList = getFiles([ROOT, 'hrefArray', TRASH]); - var fData = files[FILES_DATA]; getFiles([FILES_DATA]).forEach(function (id) { if (filesList.indexOf(id) === -1) { - removePadAttribute(fData[id].href); spliceFileData(id); } }); @@ -1014,7 +1012,7 @@ define([ var toClean = []; us.forEach(function (el, idx) { if (!isFile(el, true) || rootFiles.indexOf(el) !== -1) { - toClean.push(idx); + toClean.push(el); } if (typeof el === "string") { // We have an old file (href) which is not in filesData: add it @@ -1026,12 +1024,15 @@ define([ var data = files[FILES_DATA][el]; if (!data) { debug("An element in TEMPLATE doesn't have associated data", el); - toClean.push(idx); + toClean.push(el); } } }); - toClean.forEach(function (idx) { - us.splice(idx, 1); + toClean.forEach(function (el) { + var idx = us.indexOf(el); + if (idx !== -1) { + us.splice(idx, 1); + } }); }; var migrateAttributes = function (el, id, parsed) { diff --git a/www/drive/file.less b/www/drive/file.less index 46aadaf77..42019501f 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -495,6 +495,15 @@ span { width: 100%; margin-top: 5px; } + .state { + position: absolute; + top: 3px; + right: 3px; + .fa { + margin:0; + font-size: 18px; + } + } } .listElement { display: none; @@ -566,7 +575,12 @@ span { overflow: hidden; white-space: nowrap; box-sizing: border-box; - &.icon { + &.state { + .fa:not(:last-child) { + margin-right: 5px; + } + } + &.icon, &.state { width: 30px; } &.type, &.atime, &.ctime { diff --git a/www/drive/main.js b/www/drive/main.js index 22ae766a4..f415ad49e 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -176,6 +176,8 @@ define([ var $backupIcon = $('', {"class": "fa fa-life-ring"}); var $searchIcon = $('', {"class": "fa fa-search searchIcon"}); var $addIcon = $('', {"class": "fa fa-plus"}); + var $renamedIcon = $('', {"class": "fa fa-flag"}); + var $readonlyIcon = $('', {"class": "fa fa-eye"}); var history = { isHistoryMode: false, @@ -1119,19 +1121,27 @@ define([ var data = filesOp.getFileData(element); if (!data) { return void logError("No data for the file", element); } + var hrefData = Cryptpad.parsePadUrl(data.href); + var $state = $('', {'class': 'state'}); + if (hrefData.hashData && hrefData.hashData.mode === 'view') { + var $ro = $readonlyIcon.clone().appendTo($state); + $ro.attr('title', Messages.readonly); + } + if (data.filename && data.filename !== data.title) { + var $renamed = $renamedIcon.clone().appendTo($state); + $renamed.attr('title', "TODO: you've set a custom name for this pad. Its shared title is:\n{0}"); + } + var name = filesOp.getTitle(element); // The element with the class '.name' is underlined when the 'li' is hovered var $name = $('', {'class': 'name'}).text(name); $span.html(''); $span.append($name); + $span.append($state); - var hrefData = Cryptpad.parsePadUrl(data.href); var type = Messages.type[hrefData.type] || hrefData.type; var $type = $('', {'class': 'type listElement'}).text(type); - if (hrefData.hashData && hrefData.hashData.mode === 'view') { - $type.append(' (' + Messages.readonly+ ')'); - } var $adate = $('', {'class': 'atime listElement'}).text(getDate(data.atime)); var $cdate = $('', {'class': 'ctime listElement'}).text(getDate(data.ctime)); $span.append($type); @@ -1147,9 +1157,10 @@ define([ var sf = filesOp.hasSubfolder(element); var files = filesOp.hasFile(element); var $name = $('', {'class': 'name'}).text(key); + var $state = $('', {'class': 'state'}); var $subfolders = $('', {'class': 'folders listElement'}).text(sf); var $files = $('', {'class': 'files listElement'}).text(files); - $span.append($name).append($subfolders).append($files); + $span.append($name).append($state).append($subfolders).append($files); }; // This is duplicated in cryptpad-common, it should be unified @@ -1542,9 +1553,11 @@ define([ //var $fohElement = $('', {'class': 'element'}).appendTo($folderHeader); var $fhIcon = $('', {'class': 'icon'}); var $name = $('', {'class': 'name foldername clickable'}).text(Messages.fm_folderName).click(onSortByClick); + var $state = $('', {'class': 'state'}); var $subfolders = $('', {'class': 'folders listElement'}).text(Messages.fm_numberOfFolders); var $files = $('', {'class': 'files listElement'}).text(Messages.fm_numberOfFiles); - $fohElement.append($fhIcon).append($name).append($subfolders).append($files); + $fohElement.append($fhIcon).append($name).append($state) + .append($subfolders).append($files); addFolderSortIcon($fohElement); return $fohElement; }; @@ -1566,11 +1579,12 @@ define([ //var $fihElement = $('', {'class': 'element'}).appendTo($fileHeader); var $fhIcon = $('', {'class': 'icon'}); var $fhName = $('', {'class': 'name filename clickable'}).text(Messages.fm_fileName).click(onSortByClick); + var $fhState = $('', {'class': 'state'}); var $fhType = $('', {'class': 'type clickable'}).text(Messages.fm_type).click(onSortByClick); var $fhAdate = $('', {'class': 'atime clickable'}).text(Messages.fm_lastAccess).click(onSortByClick); var $fhCdate = $('', {'class': 'ctime clickable'}).text(Messages.fm_creation).click(onSortByClick); // If displayTitle is false, it means the "name" is the title, so do not display the "name" header - $fihElement.append($fhIcon).append($fhName).append($fhType); + $fihElement.append($fhIcon).append($fhName).append($fhState).append($fhType); if (!isWorkgroup()) { $fihElement.append($fhAdate).append($fhCdate); } diff --git a/www/register/main.js b/www/register/main.js index d302a0634..e8fdb8d22 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -115,6 +115,15 @@ define([ var doesAccept = $checkAcceptTerms[0].checked; /* basic validation */ + if (!Cred.isLongEnoughPassword(passwd)) { + var warning = Messages._getKey('register_passwordTooShort', [ + Cred.MINIMUM_PASSWORD_LENGTH + ]); + return void Cryptpad.alert(warning, function () { + registering = false; + }); + } + if (passwd !== confirmPassword) { // do their passwords match? return void Cryptpad.alert(Messages.register_passwordsDontMatch); }