Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging

This commit is contained in:
ansuz 2019-04-17 14:46:57 +02:00
commit b8343b5483
15 changed files with 112 additions and 64 deletions

View file

@ -5,6 +5,7 @@ var map = {
'es': 'Español',
'el': 'Ελληνικά',
'fr': 'Français',
'nb': 'Norwegian Bokmål',
'pl': 'Polski',
'pt-br': 'Português do Brasil',
'ro': 'Română',

View file

@ -0,0 +1,14 @@
/*
* You can override the translation text using this file.
* The recommended method is to make a copy of this file (/customize.dist/translations/messages.{LANG}.js)
in a 'customize' directory (/customize/translations/messages.{LANG}.js).
* If you want to check all the existing translation keys, you can open the internal language file
but you should not change it directly (/common/translations/messages.{LANG}.js)
*/
define(['/common/translations/messages.nb.js'], function (Messages) {
// Replace the existing keys in your copied file here:
// Messages.button_newpad = "New Rich Text Document";
return Messages;
});

View file

@ -58147,37 +58147,6 @@ function Log(level) {
this.warn = function () {};
this.error = function () {};
this.log = function () {};
return;
this.log = function () {
var args = Array.prototype.slice.call(arguments);
var level = args.shift();
var logLevel = this.level;
if (typeof logLevel === 'undefined') {
logLevel = defaultLevel;
}
if (logLevel <= level) {
if (typeof console !== 'undefined') {
//eslint-disable-line no-console
if (typeof console.log !== 'undefined') {
//eslint-disable-line no-console
//return console.log('[' + formatTime(new Date()) + '] ' , str); //eslint-disable-line no-console
args.unshift('[' + formatTime(new Date()) + '] ');
console.log.apply(console, args.map(function (a) {
if (typeof a === "object") {
return a.toString() + JSON.stringify(a, null, 2);
}
return a;
}));
}
}
}
};
this.trace = window.console.debug.bind(window.console, format('TRACE', name), 'color:grey;', 'color: grey;');
this.debug = window.console.debug.bind(window.console, format('DEBUG', name), 'color:grey;', 'color: green;');
this.info = window.console.debug.bind(window.console, format('INFO', name), 'color:grey;', 'color: blue;');
this.warn = window.console.debug.bind(window.console, format('WARN', name), 'color:grey;', 'color: orange;');
this.error = window.console.debug.bind(window.console, format('ERROR', name), 'color:grey;', 'color: red;');
}
exports.Log = Log;

View file

@ -965,6 +965,7 @@ define([
if (channel.padChan !== padChan) { return; }
if (channel.wc) { channel.wc.leave(); }
channel.stopped = true;
delete channels[chatChan];
return true;
});
};

View file

@ -1058,14 +1058,12 @@ define([
};
var timeout = false;
common.onTimeoutEvent = Util.mkEvent();
var onTimeout = function () {
return;
/*
timeout = true;
common.onNetworkDisconnect.fire();
// FIXME: no UI in outer...
window.alert("Timeout error, please reload this tab");
*/
common.padRpc.onDisconnectEvent.fire();
common.onTimeoutEvent.fire();
};
var queries = {

View file

@ -18,6 +18,25 @@ define(['json.sortify'], function (Sortify) {
var lazyChangeHandlers = [];
var titleChangeHandlers = [];
// When someone leaves the document, their metadata is removed from our metadataObj
// but it is not removed instantly from the chainpad document metadata. This is
// the result of the lazy object: if we had to remove the metadata instantly, all
// the remaining members would try to push a patch to do it, and it could create
// conflicts. Their metadata is instead removed from the chainpad doc only when
// someone calls onLocal to make another change.
// The leaving user is not visible in the userlist UI because we filter it using
// the list of "members" (netflux ID currently online).
// Our Problem:
// With the addition of shared workers, a user can leave and join back with the same
// netflux ID (just reload the pad). If nobody has made any change in the mean time,
// their metadata will still be in the document, but they won't be in our metadataObj.
// This causes the presence of a "viewer" instead of an editor, because they don't
// have user data.
// To fix this problem, the metadata manager can request "syncs" from a chainpad app,
// and the app should trigger a "metadataMgr.updateMetadata(data)" in the handler.
// See "metadataMgr.onRequestSync" in sframe-app-framework for an example.
var syncHandlers = [];
var rememberedTitle;
var checkUpdate = function (lazy) {
@ -41,26 +60,25 @@ define(['json.sortify'], function (Sortify) {
var mdo = {};
// We don't want to add our user data to the object multiple times.
//var containsYou = false;
//console.log(metadataObj);
Object.keys(metadataObj.users).forEach(function (x) {
if (members.indexOf(x) === -1) { return; }
mdo[x] = metadataObj.users[x];
/*if (metadataObj.users[x].uid === meta.user.uid) {
//console.log('document already contains you');
containsYou = true;
}*/
});
//if (!containsYou) { mdo[meta.user.netfluxId] = meta.user; }
if (!priv.readOnly) {
mdo[meta.user.netfluxId] = meta.user;
}
metadataObj.users = mdo;
// Always update the userlist in the lazy object, otherwise it may be outdated
// and metadataMgr.updateMetadata() won't do anything, and so we won't push events
// to the userlist UI ==> phantom viewers
var lazyUserStr = Sortify(metadataLazyObj.users[meta.user.netfluxId]);
dirty = false;
if (lazy || lazyUserStr !== Sortify(meta.user)) {
metadataLazyObj = JSON.parse(JSON.stringify(metadataObj));
lazyChangeHandlers.forEach(function (f) { f(); });
} else {
metadataLazyObj.users = JSON.parse(JSON.stringify(mdo));
}
if (metadataObj.title !== rememberedTitle) {
@ -127,6 +145,7 @@ define(['json.sortify'], function (Sortify) {
members.push(ev);
if (!meta.user) { return; }
change(false);
syncHandlers.forEach(function (f) { f(); });
});
sframeChan.on('EV_RT_LEAVE', function (ev) {
var idx = members.indexOf(ev);
@ -171,13 +190,14 @@ define(['json.sortify'], function (Sortify) {
onTitleChange: function (f) { titleChangeHandlers.push(f); },
onChange: function (f) { changeHandlers.push(f); },
onChangeLazy: function (f) { lazyChangeHandlers.push(f); },
onRequestSync: function (f) { syncHandlers.push(f); },
isConnected : function () {
return members.indexOf(meta.user.netfluxId) !== -1;
},
getViewers : function () {
checkUpdate(false);
var list = members.slice().filter(function (m) { return m.length === 32; });
return list.length - Object.keys(metadataObj.users).length;
return list.length - Object.keys(metadataLazyObj.users).length;
},
getChannelMembers: function () { return members.slice(); },
getPrivateData : function () {

View file

@ -1262,9 +1262,15 @@ define([
var messengerEventClients = [];
var dropChannel = function (chanId) {
store.messenger.leavePad(chanId);
store.cursor.leavePad(chanId);
store.onlyoffice.leavePad(chanId);
try {
store.messenger.leavePad(chanId);
} catch (e) { console.error(e); }
try {
store.cursor.leavePad(chanId);
} catch (e) { console.error(e); }
try {
store.onlyoffice.leavePad(chanId);
} catch (e) { console.error(e); }
if (!Store.channels[chanId]) { return; }
@ -1283,8 +1289,12 @@ define([
if (messengerIdx !== -1) {
messengerEventClients.splice(messengerIdx, 1);
}
store.cursor.removeClient(clientId);
store.onlyoffice.removeClient(clientId);
try {
store.cursor.removeClient(clientId);
} catch (e) { console.error(e); }
try {
store.onlyoffice.removeClient(clientId);
} catch (e) { console.error(e); }
Object.keys(Store.channels).forEach(function (chanId) {
var chanIdx = Store.channels[chanId].clients.indexOf(clientId);
@ -1602,12 +1612,11 @@ define([
broadcast([], 'NETWORK_RECONNECT', {myId: info.myId});
});
/*
// Ping clients regularly to make sure one tab was not closed without sending a removeClient()
// command. This allow us to avoid phantom viewers in pads.
var PING_INTERVAL = 30000;
var MAX_PING = 1000;
var MAX_FAILED_PING = 5;
var MAX_PING = 5000;
var MAX_FAILED_PING = 2;
setInterval(function () {
var clients = [];
@ -1635,7 +1644,6 @@ define([
ping();
});
}, PING_INTERVAL);
*/
};
/**

View file

@ -533,6 +533,12 @@ define([
}
};
cpNfInner.metadataMgr.onChange(checkReady);
cpNfInner.metadataMgr.onRequestSync(function () {
var newContentStr = cpNfInner.chainpad.getUserDoc();
var newContent = JSON.parse(newContentStr);
var meta = extractMetadata(newContent);
cpNfInner.metadataMgr.updateMetadata(meta);
});
checkReady();
var infiniteSpinnerModal = false;

View file

@ -269,6 +269,9 @@ define([
sessionStorage[Utils.Constants.displayPadCreationScreen];
delete sessionStorage[Utils.Constants.displayPadCreationScreen];
var updateMeta = function () {
// TODO availableHashes in privateData may need updates once we have
// a better privileges workflow
//console.log('EV_METADATA_UPDATE');
var metaObj, isTemplate;
nThen(function (waitFor) {
@ -874,6 +877,10 @@ define([
Cryptpad.cursor.execCommand(data, cb);
});
Cryptpad.onTimeoutEvent.reg(function () {
sframeChan.event('EV_WORKER_TIMEOUT');
});
if (cfg.messaging) {
Notifier.getPermission();

View file

@ -51,14 +51,16 @@ define([
metadataMgr.onChange(function () {
var md = metadataMgr.getMetadata();
if ($title) {
$title.find('span.cp-toolbar-title-value').text(md.title || md.defaultTitle);
$title.find('input').val(md.title || md.defaultTitle);
$title.find('input').prop('placeholder', md.defaultTitle);
}
exp.defaultTitle = md.defaultTitle;
exp.title = md.title;
});
metadataMgr.onTitleChange(function (title, defaultTitle) {
if ($title) {
$title.find('span.cp-toolbar-title-value').text(title || defaultTitle);
$title.find('input').val(title || defaultTitle);
}
exp.title = title;
sframeChan.query('Q_SET_PAD_TITLE_IN_DRIVE', {
title: title,
defaultTitle: defaultTitle

View file

@ -613,6 +613,10 @@ define([
});
});
ctx.sframeChan.on('EV_WORKER_TIMEOUT', function () {
UI.errorLoadingScreen(Messages.timeoutError);
});
ctx.sframeChan.on('EV_CHROME_68', function () {
UI.alert(Messages.chrome68);
});

View file

@ -475,11 +475,11 @@ MessengerUI, Messages) {
};
$closeIcon.click(function () {
Common.setAttribute(['toolbar', 'chat-drawer'], false);
hide();
hide(true);
});
$button.click(function () {
var visible = $content.is(':visible');
if (visible) { hide(); }
if (visible) { hide(true); }
else { show(); }
visible = !visible;
Common.setAttribute(['toolbar', 'chat-drawer'], visible);

View file

@ -0,0 +1,2 @@
{
}

View file

@ -143,7 +143,7 @@
"tags_notShared": "Ваши теги не разделяются с другими пользователями",
"button_newsheet": "Новый Лист",
"newButtonTitle": "Создать новый блокнот",
"useTemplateCancel": "Начать без образца (Esc)",
"useTemplateCancel": "Начать заново (Esc)",
"previewButtonTitle": "Отобразить или скрыть режим предпросмотра разметки",
"printOptions": "Опции расположения",
"printBackgroundValue": "<b>Текущий фон:</b> <em>{0}</em>",
@ -163,7 +163,7 @@
"editOpen": "Открыть редактируемую ссылку в новой вкладке",
"editOpenTitle": "Открыть блокнот в режиме редактирования в новой вкладке",
"viewShare": "Ссылка только для чтения",
"viewShareTitle": "Копировать ссылку для чтения",
"viewShareTitle": "Скопировать ссылку для чтения в буфер обмена",
"viewOpen": "Открыть ссылку в режиме чтения в новой вкладке",
"viewOpenTitle": "Открыть блокнот в режиме чтения в новой вкладке",
"fileShare": "Скопировать ссылку",
@ -204,10 +204,10 @@
"kanban_working": "В процессе",
"kanban_deleteBoard": "Вы уверены, что хотите удалить эту доску?",
"kanban_addBoard": "Добавить доску",
"kanban_removeItem": "",
"poll_p_save": "Ваши настройки применяются мгновенно, так что вам не нужно их сохранять",
"kanban_removeItem": "Удалить этот элемент",
"poll_p_save": "Ваши настройки применяются мгновенно, так что вам не нужно их сохранять.",
"wizardTitle": "Используйте помощник, чтобы создать опрос",
"wizardConfirm": "Вы хотите добавить эти варианты в опрос?",
"wizardConfirm": "Вы действительно хотите добавить эти варианты в ваш опрос?",
"poll_publish_button": "Опубликовать",
"poll_admin_button": "Админ",
"poll_create_user": "Добавить нового пользователя",
@ -305,5 +305,17 @@
"crowdfunding_popup_no": "Не сейчас",
"crowdfunding_popup_never": "Не спрашивать меня снова",
"markdown_toc": "Содержимое",
"fm_expirablePad": "Этот блокнот удалится через {0}"
"fm_expirablePad": "Этот блокнот удалится через {0}",
"fileEmbedTitle": "Вставить файл во внешнюю страницу",
"kanban_removeItemConfirm": "Вы уверенны, что хотите удалить этот пункт?",
"settings_backup2": "Скачать мой CryptDrive",
"settings_backup2Confirm": "Это позволит скачать все пэды и файлы с вашего CryptDrive. Если вы хотите продолжить, выберите имя и нажмите OK",
"settings_exportTitle": "Экспортировать Ваш CryptDrive",
"fileEmbedScript": "Чтобы вставить этот файл, включите этот скрипт один раз на своей странице, чтобы загрузить медиатег:",
"fileEmbedTag": "Затем поместите медиатег в любое место на странице, куда вы хотите его вставить:",
"pad_mediatagRatio": "Оставить соотношение",
"kanban_item": "Элемент {0}",
"poll_p_encryption": "Все ваши данные зашифрованы, доступ к ним имеют только пользователи, имеющие доступ к этой ссылке. Даже сервер не видит, что вы меняете.",
"wizardLog": "Нажмите кнопку в левом верхнем углу, чтобы вернуться к опросу",
"poll_bookmark_col": "Добавить этот столбец в закладку, чтобы он всегда был разблокирован и отображался для вас в начале"
}

View file

@ -1158,6 +1158,10 @@ define([
var md = copyObject(metadataMgr.getMetadata());
APP.proxy.metadata = md;
});
metadataMgr.onRequestSync(function () {
var meta = JSON.parse(JSON.stringify(APP.proxy.metadata));
metadataMgr.updateMetadata(meta);
});
/* add a forget button */
var forgetCb = function (err) {