diff --git a/customize.dist/about.html b/customize.dist/about.html index 5593e41b9..03032969b 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -2,7 +2,7 @@ - Cryptpad: Zero Knowledge, Collaborative Real Time Editing + CryptPad: Zero Knowledge, Collaborative Real Time Editing diff --git a/customize.dist/contact.html b/customize.dist/contact.html index 5593e41b9..03032969b 100644 --- a/customize.dist/contact.html +++ b/customize.dist/contact.html @@ -2,7 +2,7 @@ - Cryptpad: Zero Knowledge, Collaborative Real Time Editing + CryptPad: Zero Knowledge, Collaborative Real Time Editing diff --git a/customize.dist/index.html b/customize.dist/index.html index 5593e41b9..03032969b 100644 --- a/customize.dist/index.html +++ b/customize.dist/index.html @@ -2,7 +2,7 @@ - Cryptpad: Zero Knowledge, Collaborative Real Time Editing + CryptPad: Zero Knowledge, Collaborative Real Time Editing diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 5e26bbe83..5ddbb27c9 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -162,7 +162,7 @@ define([ ]) ]), h('button.btn.btn-secondary.login.half.first', Msg.login_login), - h('button.btn.btn-success.register.half.first', Msg.login_register), + h('button.btn.btn-success.register.half', Msg.login_register), h('p.separator', Msg.login_orNoLogin), h('p#buttons.buttons'), h('p.driveLink', [ @@ -363,7 +363,7 @@ define([ h('button.btn.btn-primary.login.first', Msg.login_login), h('div.extra', [ h('p', Msg.login_notRegistered), - h('button#register.btn.btn-success.register.first', Msg.login_register) + h('button#register.btn.btn-success.register', Msg.login_register) ]) ]) ]) diff --git a/customize.dist/privacy.html b/customize.dist/privacy.html index 5593e41b9..03032969b 100644 --- a/customize.dist/privacy.html +++ b/customize.dist/privacy.html @@ -2,7 +2,7 @@ - Cryptpad: Zero Knowledge, Collaborative Real Time Editing + CryptPad: Zero Knowledge, Collaborative Real Time Editing diff --git a/customize.dist/src/less/cryptpad.less b/customize.dist/src/less/cryptpad.less index 106c57ab2..b29ae4107 100644 --- a/customize.dist/src/less/cryptpad.less +++ b/customize.dist/src/less/cryptpad.less @@ -421,6 +421,8 @@ noscript { label { margin-bottom: 0; + margin-left: 5px; + vertical-align: middle; } button { @@ -428,7 +430,7 @@ noscript { width: 100%; cursor: pointer; &.half { - width: ~"calc(50% - 2px)"; + width: ~"calc(50% - 10px)"; &:not(.first) { float: right; } diff --git a/customize.dist/src/template.html b/customize.dist/src/template.html index 5593e41b9..03032969b 100644 --- a/customize.dist/src/template.html +++ b/customize.dist/src/template.html @@ -2,7 +2,7 @@ - Cryptpad: Zero Knowledge, Collaborative Real Time Editing + CryptPad: Zero Knowledge, Collaborative Real Time Editing diff --git a/customize.dist/terms.html b/customize.dist/terms.html index 5593e41b9..03032969b 100644 --- a/customize.dist/terms.html +++ b/customize.dist/terms.html @@ -2,7 +2,7 @@ - Cryptpad: Zero Knowledge, Collaborative Real Time Editing + CryptPad: Zero Knowledge, Collaborative Real Time Editing diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index ae82b0052..01623ccb0 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -485,5 +485,32 @@ define(function () { out.canvas_opacityLabel = "Opacidad: {0}"; out.canvas_widthLabel = "Talla: {0}"; + // 1.10.0 - Kraken + + out.moreActions = "Más acciones"; + out.importButton = "Importar"; + out.exportButton = "Exportar"; + out.saveTitle = "Guardar título (enter)"; + out.forgetButton = "Eliminar"; + out.printText = "Imprimir"; + out.slideOptionsText = "Opciones"; + out.historyText = "Historial"; + out.openLinkInNewTab = "Abrir enlace en pestaña nueva"; + out.profileButton = "Perfíl"; + out.profile_urlPlaceholder = "URL"; + out.profile_namePlaceholder = "Nombre mostrado en su perfíl"; + out.profile_avatar = "Imágen"; + out.profile_upload = "Subir una imágen"; + out.profile_error = "Error al crear tu perfíl: {0}"; + out.profile_register = "Tienes que registrarte para crear perfíl"; + out.profile_create = "Crear perfíl"; + out.profile_description = "Descripción"; + out.profile_fieldSaved = "Guardado: {0}"; + out.download_mt_button = "Descargar"; + out.updated_0_header_logoTitle = "Volver a tu CryptDrive"; + out.header_logoTitle = out.updated_0_header_logoTitle; + + + return out; }); diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 02f682d4d..6fc608855 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -36,6 +36,8 @@ define(function () { out.synced = "Everything is saved"; out.deleted = "Pad deleted from your CryptDrive"; + out.realtime_unrecoverableError = "The realtime engine has encountered an unrecoverable error. Click OK to reload."; + out.disconnected = 'Disconnected'; out.synchronizing = 'Synchronizing'; out.reconnecting = 'Reconnecting...'; diff --git a/pinneddata.js b/pinneddata.js index 8dbbc7fec..2ecf8605d 100644 --- a/pinneddata.js +++ b/pinneddata.js @@ -30,7 +30,7 @@ const sizeForHashes = (hashes, dsFileStats) => { let sum = 0; hashes.forEach((h) => { const s = dsFileStats[h]; - if (typeof(s) !== 'number') { + if (typeof(s) !== 'object' || typeof(s.size) !== 'number') { //console.log('missing ' + h + ' ' + typeof(s)); } else { sum += s.size; @@ -62,11 +62,26 @@ nThen((waitFor) => { }); }); }).nThen((waitFor) => { + + Fs.readdir('./blob', waitFor((err, list) => { + if (err) { throw err; } + dirList = list; + })); +}).nThen((waitFor) => { + dirList.forEach((f) => { + sema.take((returnAfter) => { + Fs.readdir('./blob/' + f, waitFor(returnAfter((err, list2) => { + if (err) { throw err; } + list2.forEach((ff) => { fileList.push('./blob/' + f + '/' + ff); }); + }))); + }); + }); +}).nThen((waitFor) => { fileList.forEach((f) => { sema.take((returnAfter) => { Fs.stat(f, waitFor(returnAfter((err, st) => { if (err) { throw err; } - dsFileStats[f.replace(/^.*\/([^\/]*)\.ndjson$/, (all, a) => (a))] = st; + dsFileStats[f.replace(/^.*\/([^\/\.]*)(\.ndjson)?$/, (all, a) => (a))] = st; }))); }); }); diff --git a/readme.md b/readme.md index 2c5b6e895..220891324 100644 --- a/readme.md +++ b/readme.md @@ -129,7 +129,7 @@ Still there are other low-lives in the world so using CryptPad over HTTPS is pro ## Setup using Docker -See [Cryptpad-Docker](cryptpad-docker.md) +See [Cryptpad-Docker](docs/cryptpad-docker.md) ## Translations diff --git a/rpc.js b/rpc.js index 5b5d058b9..96ed2cde1 100644 --- a/rpc.js +++ b/rpc.js @@ -113,15 +113,21 @@ var isTooOld = function (time, now) { return (now - time) > 300000; }; +var expireSession = function (Sessions, key) { + var session = Sessions[key]; + if (!session) { return; } + if (session.blobstage) { + session.blobstage.close(); + } + delete Sessions[key]; +}; + var expireSessions = function (Sessions) { var now = +new Date(); Object.keys(Sessions).forEach(function (key) { var session = Sessions[key]; - if (isTooOld(Sessions[key].atime, now)) { - if (session.blobstage) { - session.blobstage.close(); - } - delete Sessions[key]; + if (session && isTooOld(session.atime, now)) { + expireSession(Sessions, key); } }); }; @@ -846,6 +852,7 @@ var isAuthenticatedCall = function (call) { 'GET_LIMIT', 'UPLOAD_COMPLETE', 'UPLOAD_CANCEL', + 'EXPIRE_SESSION', ].indexOf(call) !== -1; }; @@ -1046,7 +1053,11 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function) } Respond(void 0, dict); }); - + case 'EXPIRE_SESSION': + return void setTimeout(function () { + expireSession(Sessions, safeKey); + Respond(void 0, "OK"); + }); // restricted to privileged users... case 'UPLOAD': if (!privileged) { return deny(); } diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 1b6912a57..89a7feff1 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -159,6 +159,9 @@ define([ } }; + var randomToken = function () { + return Math.random().toString(16).replace(/0./, ''); + }; var feedback = common.feedback = function (action, force) { if (force !== true) { if (!action) { return; } @@ -167,7 +170,7 @@ define([ } catch (e) { return void console.error(e); } } - var href = '/common/feedback.html?' + action + '=' + (+new Date()); + var href = '/common/feedback.html?' + action + '=' + randomToken(); $.ajax({ type: "HEAD", url: href, @@ -199,13 +202,29 @@ define([ return; }; + common.infiniteSpinnerDetected = false; var whenRealtimeSyncs = common.whenRealtimeSyncs = function (realtime, cb) { realtime.sync(); + window.setTimeout(function () { if (realtime.getAuthDoc() === realtime.getUserDoc()) { return void cb(); } + + var to = setTimeout(function () { + realtime.abort(); + // don't launch more than one popup + if (common.infiniteSpinnerDetected) { return; } + + // inform the user their session is in a bad state + common.confirm(Messages.realtime_unrecoverableError, function (yes) { + if (!yes) { return; } + window.location.reload(); + }); + common.infiniteSpinnerDetected = true; + }, 30000); realtime.onSettle(function () { + clearTimeout(to); cb(); }); }, 0); diff --git a/www/drive/file.less b/www/drive/file.less index 9bb4eccf4..c9e36e7b2 100644 --- a/www/drive/file.less +++ b/www/drive/file.less @@ -416,6 +416,11 @@ span { } .path { font-style: italic; + direction: rtl; + .element { + display: inline-block; + margin-right: 5px; + } } .title { font-weight: bold; diff --git a/www/drive/main.js b/www/drive/main.js index d31c701a6..d43c9e7f9 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -528,6 +528,12 @@ define([ module.displayDirectory(currentPath); }; + var getFileNameExtension = function (name) { + var matched = /\.\S+$/.exec(name); + if (matched && matched.length) { return matched[matched.length -1]; } + return ''; + }; + // Replace a file/folder name by an input to change its value var displayRenameInput = function ($element, path) { // NOTE: setTimeout(f, 0) otherwise the "rename" button in the toolbar is not working @@ -551,6 +557,7 @@ define([ value: name }).data('path', path); + // Stop propagation on keydown to avoid issues with arrow keys $input.on('keydown', function (e) { e.stopPropagation(); }); @@ -567,7 +574,12 @@ define([ //$element.parent().append($input); $name.after($input); $input.focus(); - $input.select(); + + var extension = getFileNameExtension(name); + var input = $input[0]; + input.selectionStart = 0; + input.selectionEnd = name.length - extension.length; + // We don't want to open the file/folder when clicking on the input $input.on('click dblclick', function (e) { removeSelected(); @@ -1250,12 +1262,11 @@ define([ }; // Create the title block with the "parent folder" button - var createTitle = function (path, noStyle) { + var createTitle = function ($container, path, noStyle) { if (!path || path.length === 0) { return; } var isTrash = filesOp.isPathIn(path, [TRASH]); - var $title = $driveToolbar.find('.path'); - if (APP.mobile()) { - return $title; + if (APP.mobile() && !noStyle) { // noStyle means title in search result + return $container; } var el = path[0] === SEARCH ? undefined : filesOp.find(path); path = path[0] === SEARCH ? path.slice(0,1) : path; @@ -1281,12 +1292,11 @@ define([ if (idx === 0) { name = getPrettyName(p); } else { var $span2 = $('', {'class': 'element separator'}).text(' / '); - $title.prepend($span2); + $container.prepend($span2); } - $span.text(name).prependTo($title); + $span.text(name).prependTo($container); }); - return $title; }; var createInfoBox = function (path) { @@ -1764,7 +1774,8 @@ define([ path.pop(); path.push(r.data.title); } - var $path = $('', {'class': 'col1 path'}).html(createTitle(path, true).html()); + var $path = $('', {'class': 'col1 path'}); + createTitle($path, path, true); var parentPath = path.slice(); var $a; if (parentPath) { @@ -1859,7 +1870,7 @@ define([ // NewButton can be undefined if we're in read only mode createNewButton(isInRoot, $toolbar.find('.leftside')); - createTitle(path).appendTo($toolbar.find('.path')); + createTitle($toolbar.find('.path'), path); if (APP.mobile()) { var $context = $('