- 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 = $('