diff --git a/customize.dist/messages.js b/customize.dist/messages.js
index fb613d591..629a87054 100644
--- a/customize.dist/messages.js
+++ b/customize.dist/messages.js
@@ -50,9 +50,26 @@ define(req, function(Default, Language) {
var langs = arguments;
Object.keys(externalMap).forEach(function (code, i) {
var translation = langs[i];
+ var updated = {};
+ Object.keys(Default).forEach(function (k) {
+ if (/^updated_[0-9]+_/.test(k) && !translation[k]) {
+ var key = k.split('_').slice(2).join('_');
+ // Make sure we don't already have an update for that key. It should not happen
+ // but if it does, keep the latest version
+ if (updated[key]) {
+ var ek = updated[key];
+ if (parseInt(ek.split('_')[1]) > parseInt(k.split('_')[1])) { return; }
+ }
+ updated[key] = k;
+ }
+ });
Object.keys(Default).forEach(function (k) {
if (/^_/.test(k)) { return; }
- if (!translation[k]) {
+ if (!translation[k] || updated[k]) {
+ if (updated[k]) {
+ missing.push([code, k, 2, 'out.' + updated[k]]);
+ return;
+ }
missing.push([code, k, 1]);
}
});
@@ -62,10 +79,6 @@ define(req, function(Default, Language) {
missing.push([code, k, 0]);
}
});
- /*if (typeof(translation._languageName) !== 'string') {
- var warning = 'key [_languageName] is missing from translation [' + code + ']';
- missing.push(warning);
- }*/
});
cb(missing);
});
diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js
index d9f6a8544..c24e1df7c 100644
--- a/customize.dist/translations/messages.es.js
+++ b/customize.dist/translations/messages.es.js
@@ -12,7 +12,8 @@ define(function () {
out.type.poll = 'Encuesta';
out.type.slide = 'Presentación';
- out.common_connectionLost = "Connexión perdida
El documento está ahora en modo solo lectura hasta que la conexión vuelva.";
+ out.updated_0_common_connectionLost = "Connexión perdida
El documento está ahora en modo solo lectura hasta que la conexión vuelva.";
+ out.common_connectionLost = out.updated_0_common_connectionLost;
out.disconnected = "Desconectado";
out.synchronizing = "Sincronización";
diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js
index 1ad5e907d..b96d497d3 100644
--- a/customize.dist/translations/messages.fr.js
+++ b/customize.dist/translations/messages.fr.js
@@ -16,7 +16,8 @@ define(function () {
out.button_newpoll = 'Nouveau sondage';
out.button_newslide = 'Nouvelle présentation';
- out.common_connectionLost = "Connexion au serveur perdue
Vous êtes désormais en mode lecture seule jusqu'au retour de la connexion.";
+ out.updated_0_common_connectionLost = "Connexion au serveur perdue
Vous êtes désormais en mode lecture seule jusqu'au retour de la connexion.";
+ out.common_connectionLost = out.updated_0_common_connectionLost;
out.websocketError = 'Impossible de se connecter au serveur WebSocket...';
out.typeError = "Ce document temps-réel n'est pas compatible avec l'application sélectionnée";
diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js
index 30b051634..abfec9239 100644
--- a/customize.dist/translations/messages.js
+++ b/customize.dist/translations/messages.js
@@ -18,8 +18,8 @@ define(function () {
// NOTE: We want to update the 'common_connectionLost' key.
// Please do not add a new 'updated_common_connectionLostAndInfo' but change directly the value of 'common_connectionLost'
- out.updated_common_connectionLostAndInfo = "Server Connection Lost
You're now in read-only mode until the connection is back.";
- out.common_connectionLost = out.updated_common_connectionLostAndInfo;
+ out.updated_0_common_connectionLost = "Server Connection Lost
You're now in read-only mode until the connection is back.";
+ out.common_connectionLost = out.updated_0_common_connectionLost;
out.websocketError = 'Unable to connect to the websocket server...';
out.typeError = "That realtime document is not compatible with the selected application";
diff --git a/www/assert/main.js b/www/assert/main.js
index 51bdf00a8..b6a1fbd45 100644
--- a/www/assert/main.js
+++ b/www/assert/main.js
@@ -141,22 +141,6 @@ define([
strungJSON(orig);
});
- assert(function () {
- var todo = function (missing) {
- if (missing.length !== 0) {
- missing.forEach(function (msg) {
- console.log('* ' + msg);
- });
-
- // No, this is crappy, it's going to cause tests to fail basically all of the time.
- //return false;
- }
- };
- Cryptpad.Messages._checkTranslationState(todo);
-
- return true;
- }, "expected all translation keys in default language to be present in all translations. See console for details.");
-
var swap = function (str, dict) {
return str.replace(/\{\{(.*?)\}\}/g, function (all, key) {
return typeof dict[key] !== 'undefined'? dict[key] : all;
diff --git a/www/assert/translations/main.js b/www/assert/translations/main.js
index 1b1683afe..e8825d422 100644
--- a/www/assert/translations/main.js
+++ b/www/assert/translations/main.js
@@ -21,6 +21,7 @@ define([
var code = msg[0];
var key = msg[1];
var needed = msg[2];
+ var value = msg[3] || '""';
if (str !== code) {
if (str !== "")
@@ -38,10 +39,11 @@ define([
}
}
- res += (need ? '' : '// ') + 'out.' + key + ' = "";';
- if (need)
- {
+ res += (need ? '' : '// ') + 'out.' + key + ' = ' + value + ';';
+ if (need === 1) {
res += ' // ' + JSON.stringify(English[key]);
+ } else if (need === 2) {
+ res += ' // TODO: Key updated --> make sure the updated key "'+ value +'" exists and is translated before that one.';
}
return res;
}).join('\n')));
diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js
index b98c947f4..c03664036 100644
--- a/www/common/cryptpad-common.js
+++ b/www/common/cryptpad-common.js
@@ -706,7 +706,6 @@ define([
common.initialName = sessionStorage[newPadNameKey];
delete sessionStorage[newPadNameKey];
}
- // Deprecated
if (sessionStorage[newPadPathKey]) {
common.initialPath = sessionStorage[newPadPathKey];
delete sessionStorage[newPadPathKey];
diff --git a/www/drive/file.css b/www/drive/file.css
index bc9755009..7c907d3ed 100644
--- a/www/drive/file.css
+++ b/www/drive/file.css
@@ -392,6 +392,10 @@ span.fa-folder-open {
height: 100%;
line-height: 40px;
cursor: default;
+ width: auto;
+ overflow: hidden;
+ white-space: nowrap;
+ direction: rtl;
}
#driveToolbar .path .element {
padding: 5px;
@@ -406,3 +410,10 @@ span.fa-folder-open {
background: #fff;
border: 1px solid #888;
}
+#driveToolbar #contextButtonsContainer {
+ float: right;
+ margin: 5px;
+}
+#driveToolbar #contextButtonsContainer button {
+ vertical-align: top;
+}
diff --git a/www/drive/file.less b/www/drive/file.less
index f2f3a5ea6..95a410666 100644
--- a/www/drive/file.less
+++ b/www/drive/file.less
@@ -451,6 +451,10 @@ span {
height: 100%;
line-height: 40px;
cursor: default;
+ width: auto;
+ overflow: hidden;
+ white-space: nowrap;
+ direction: rtl;
.element {
padding: 5px;
border: 1px solid @toolbar-bg;
@@ -465,6 +469,13 @@ span {
}
}
}
+ #contextButtonsContainer {
+ float: right;
+ margin: 5px;
+ button {
+ vertical-align: top;
+ }
+ }
}
diff --git a/www/drive/inner.html b/www/drive/inner.html
index 9f337f5ff..93b06e211 100644
--- a/www/drive/inner.html
+++ b/www/drive/inner.html
@@ -19,39 +19,39 @@
diff --git a/www/drive/main.js b/www/drive/main.js
index 8bb9d1852..17ead7531 100644
--- a/www/drive/main.js
+++ b/www/drive/main.js
@@ -281,56 +281,90 @@ define([
// Replace a file/folder name by an input to change its value
var displayRenameInput = function ($element, path) {
- if (!APP.editable) { return; }
- if (!path || path.length < 2) {
- logError("Renaming a top level element (root, trash or filesData) is forbidden.");
- return;
- }
- removeInput();
- removeSelected();
- var $name = $element.find('.name');
- if (!$name.length) {
- $name = $element.find('.element');
- }
- $name.hide();
- var name = path[path.length - 1];
- var $input = $('', {
- placeholder: name,
- value: name
- });
- $input.on('keyup', function (e) {
- if (e.which === 13) {
- removeInput();
- filesOp.renameElement(path, $input.val(), function () {
- refresh();
- });
+ // NOTE: setTimeout(f, 0) otherwise the "rename" button in the toolbar is not working
+ window.setTimeout(function () {
+ if (!APP.editable) { return; }
+ if (!path || path.length < 2) {
+ logError("Renaming a top level element (root, trash or filesData) is forbidden.");
+ return;
}
- });
- //$element.parent().append($input);
- $name.after($input);
- $input.focus();
- $input.select();
- // We don't want to open the file/folder when clicking on the input
- $input.on('click dblclick', function (e) {
+ removeInput();
removeSelected();
- e.stopPropagation();
- });
- // Remove the browser ability to drag text from the input to avoid
- // triggering our drag/drop event handlers
- $input.on('dragstart dragleave drag drop', function (e) {
- e.preventDefault();
- e.stopPropagation();
- });
- // Make the parent element non-draggable when selecting text in the field
- // since it would remove the input
- $input.on('mousedown', function (e) {
- e.stopPropagation();
- $input.parents('li').attr("draggable", false);
- });
- $input.on('mouseup', function (e) {
- e.stopPropagation();
- $input.parents('li').attr("draggable", true);
- });
+ var $name = $element.find('.name');
+ if (!$name.length) {
+ $name = $element.find('.element');
+ }
+ $name.hide();
+ var name = path[path.length - 1];
+ var $input = $('', {
+ placeholder: name,
+ value: name
+ });
+ $input.on('keyup', function (e) {
+ if (e.which === 13) {
+ removeInput();
+ filesOp.renameElement(path, $input.val(), function () {
+ refresh();
+ });
+ }
+ });
+ //$element.parent().append($input);
+ $name.after($input);
+ $input.focus();
+ $input.select();
+ // We don't want to open the file/folder when clicking on the input
+ $input.on('click dblclick', function (e) {
+ removeSelected();
+ e.stopPropagation();
+ });
+ // Remove the browser ability to drag text from the input to avoid
+ // triggering our drag/drop event handlers
+ $input.on('dragstart dragleave drag drop', function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ });
+ // Make the parent element non-draggable when selecting text in the field
+ // since it would remove the input
+ $input.on('mousedown', function (e) {
+ e.stopPropagation();
+ $input.parents('li').attr("draggable", false);
+ });
+ $input.on('mouseup', function (e) {
+ e.stopPropagation();
+ $input.parents('li').attr("draggable", true);
+ });
+ },0);
+ };
+
+ var filterContextMenu = function ($menu, $element) {
+ var path = $element.data('path');
+
+ var hide = [];
+ if (!APP.editable) {
+ hide.push($menu.find('a.editable'));
+ }
+ if (!isOwnDrive()) {
+ hide.push($menu.find('a.own'));
+ }
+ if ($element.is('.file-element')) {
+ hide.push($menu.find('a.newfolder'));
+ } else {
+ hide.push($menu.find('a.open_ro'));
+ }
+ if (path && path.length > 4) {
+ hide.push($menu.find('a.restore'));
+ hide.push($menu.find('a.properties'));
+ }
+ return hide;
+ };
+
+ var updatePathSize = function () {
+ var $context = $iframe.find('#contextButtonsContainer');
+ var l = 50;
+ if ($context.length) {
+ l += $context.width() || 0;
+ }
+ $driveToolbar.find('.path').css('max-width', 'calc(100vw - '+$tree.width()+'px - '+l+'px)');
};
var updateContextButton = function () {
@@ -339,21 +373,55 @@ define([
$li = $tree.find('.element.active').closest('li');
}
var $button = $driveToolbar.find('#contextButton');
- if ($li.length !== 1
- || !$._data($li[0], 'events').contextmenu
- || $._data($li[0], 'events').contextmenu.length === 0) {
- $button.hide();
+ if ($button.length) { // mobile
+ if ($li.length !== 1
+ || !$._data($li[0], 'events').contextmenu
+ || $._data($li[0], 'events').contextmenu.length === 0) {
+ $button.hide();
+ return;
+ }
+ $button.show();
+ $button.css({
+ background: '#000'
+ });
+ window.setTimeout(function () {
+ $button.css({
+ background: ''
+ });
+ }, 500);
return;
}
- $button.show();
- $button.css({
- background: '#000'
+ // Non mobile
+ var $container = $driveToolbar.find('#contextButtonsContainer');
+ if (!$container.length) { return; }
+ $container.html('');
+ var $element = $li;
+ var $menu = $element.data('context');
+ var path = $element.data('path');
+ if (!$menu || !path) { return; }
+ var actions = [];
+ var $actions = $menu.find('a');
+ var toHide = filterContextMenu($menu, $element);
+ $actions = $actions.filter(function (i, el) {
+ for (var j = 0; j < toHide.length; j++) {
+ if ($(el).is(toHide[j])) { return false; };
+ }
+ return true;
});
- window.setTimeout(function () {
- $button.css({
- background: ''
- });
- }, 500);
+ $actions.each(function (i, el) {
+ var $a = $('