merge staging

pull/1/head
ansuz 7 years ago
commit 7aa7b82c60

1
.gitignore vendored

@ -16,4 +16,5 @@ pins/
blob/ blob/
block/ block/
blobstage/ blobstage/
block/
privileged.conf privileged.conf

@ -1,3 +1,45 @@
# Echidna release (v2.4.0)
## Goals
For version 2.4.0 we chose to use our time to address difficulties that some users had, and to release some features which have been in development for some time. With the recent release of the _password-protected-pads_ feature, some users desired to be able to change the passwords that they'd already set, or to add a password to a pad retroactively. Other users wanted to recover information that had accidentally been deleted from their pads, but found that the history feature was difficult to use on networks with poor connectivity. Others still found that loading pads in general was too slow.
## Update notes
* We have released new clientside dependencies, so server administrators will need to run `bower update`
* This release also depends on new serverside dependencies, so administrators will also need to run `npm update`
* This release (optionally) takes advantage of Webworker APIs, so administrators may need to update their Content Security Headers to include worker-src (and child-src for safari)
* see cryptpad/docs/example.nginx.conf for more details regarding configuration for nginx as a reverse proxy
* to enable webworkers as an experimental feature, add `AppConfig.disableWorkers = false;` to your `cryptpad/customize/application-config.js`
* Finally, administrators will need to restart their servers after updating, as clients will require new functionality
## What's new
### Features
* CryptPad now takes advantage of some very modern browser APIs
* Shared Workers allow common tasks for all CryptPad editors to be handled by a single background process which runs in the background. This results in better performance savings for anyone using multiple editors at once in different tabs
* Webworkers are used in situations where shared workers are not supported, for most of the same tasks. They are not shared amongst different tabs, but can allow for a more responsive user experience since some heavy commands will be run in the background
* Not all browsers feature complete support for webworkers. For cases where they are not supported at all, or where cryptographic APIs are not supported within their context (https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7607496/), we fall back to an asynchronous context in the same thread
* Pads with no password can now be updated to include a password, and pads with a password can have their passwords changed
* right-click on the pad in question, and see its properties. The following dialog will present the option to change its password
* changing a pad's password will remove its history
* Accessing a pad's history used to require that clients fetch the entire history of the pad before they could view any of it. History retrieval is now done on an on-demand basis, approximately 100 versions of the pad at a time
* this also features an updated UI with a slider
* We've refactored our whiteboard application to be compatible with our internal framework. As a result, it will be easier to maintain and will have all the same features as the other editors built with the same framework
* We've defined some new server-side features which will allow clients to change their user passwords in a coming release
* We've updated our messaging server implementation
* the aspect of the server which stores and distributes history has been untangled from the aspect which tracks user lists and broadcasts messages
* the server will now store the time when each message was received, so as to be able to allow users to view the time of edits in a later release
### Bug fixes
* When a user tries to register, but enters credentials which have already been used for that CryptPad instance, we prompt them to log in as that user. We discovered that the login had stopped working at some point. This has been fixed
* Server administrators may have seen warnings from npm when attempting to update. We have fixed invalid entries and added missing entries where appropriate such that there are no more warnings
* Static info pages have been restyled to be more responsive, thanks to @CatalinScr
* Support for friend requests in pads with version 0 hashes has been repaired
* We noticed a regression in how default titles for pads were suggested, and have implemented the intended behaviour
# Donkey release (v2.3.0) # Donkey release (v2.3.0)
## Goals ## Goals

@ -30,7 +30,7 @@
"secure-fabric.js": "secure-v1.7.9", "secure-fabric.js": "secure-v1.7.9",
"hyperjson": "~1.4.0", "hyperjson": "~1.4.0",
"chainpad-crypto": "^0.2.0", "chainpad-crypto": "^0.2.0",
"chainpad-listmap": "^0.6.0", "chainpad-listmap": "^0.5.0",
"chainpad": "^5.1.0", "chainpad": "^5.1.0",
"file-saver": "1.3.1", "file-saver": "1.3.1",
"alertifyjs": "1.0.11", "alertifyjs": "1.0.11",

@ -95,7 +95,7 @@ define([
]) ])
]) ])
]), ]),
h('div.cp-version-footer', "CryptPad v2.3.0 (Donkey)") h('div.cp-version-footer', "CryptPad v2.4.0 (Echidna)")
]); ]);
}; };

@ -37,6 +37,7 @@
line-height: 25px; line-height: 25px;
width: 100%; width: 100%;
text-align: center; text-align: center;
color: black;
} }
.cp-toolbar-history-goto { .cp-toolbar-history-goto {
display: inline-block; display: inline-block;

@ -1119,8 +1119,8 @@ define(function () {
// Change password in pad properties // Change password in pad properties
out.properties_addPassword = "Ajouter un mot de passe"; out.properties_addPassword = "Ajouter un mot de passe";
out.properties_changePassword = "Modifier le mot de passe"; out.properties_changePassword = "Modifier le mot de passe";
out.properties_confirmNew = "Êtes-vous sûr ? Ajouter un mot de passe changera l'URL de ce pad. Les utilisateurs ne connaissant pas le nouveau mot de passe perdront l'accès au pad."; out.properties_confirmNew = "Êtes-vous sûr ? Ajouter un mot de passe changera l'URL de ce pad et supprimera son historique. Les utilisateurs ne connaissant pas le nouveau mot de passe perdront l'accès au pad.";
out.properties_confirmChange = "Êtes-vous sûr ? Les utilisateurs ne connaissant pas le nouveau mot de passe perdront l'accès au pad."; out.properties_confirmChange = "Êtes-vous sûr ? Changer le mot de passe supprimera l'historique de ce pad. Les utilisateurs ne connaissant pas le nouveau mot de passe perdront l'accès au pad.";
out.properties_passwordError = "Une erreur est survenue lors de la modification du mot de passe. Veuillez réessayer."; out.properties_passwordError = "Une erreur est survenue lors de la modification du mot de passe. Veuillez réessayer.";
out.properties_passwordWarning = "Le mot de passe a été modifié avec succès mais nous n'avons pas réussi à mettre à jour votre CryptDrive avec les nouvelles informations. Vous devrez peut-être supprimer manuellement l'ancienne version de ce pad.<br>Appuyez sur OK pour recharger le pad et mettre à jour vos droits d'accès."; out.properties_passwordWarning = "Le mot de passe a été modifié avec succès mais nous n'avons pas réussi à mettre à jour votre CryptDrive avec les nouvelles informations. Vous devrez peut-être supprimer manuellement l'ancienne version de ce pad.<br>Appuyez sur OK pour recharger le pad et mettre à jour vos droits d'accès.";
out.properties_passwordSuccess = "Le mot de passe a été modifié avec succès.<br>Appuyez sur OK pour mettre à jour vos droits d'accès."; out.properties_passwordSuccess = "Le mot de passe a été modifié avec succès.<br>Appuyez sur OK pour mettre à jour vos droits d'accès.";

@ -1178,8 +1178,8 @@ define(function () {
// Change password in pad properties // Change password in pad properties
out.properties_addPassword = "Add a password"; out.properties_addPassword = "Add a password";
out.properties_changePassword = "Change the password"; out.properties_changePassword = "Change the password";
out.properties_confirmNew = "Are you sure? Adding a password will change this pad's URL. Users without the password will lose access to this pad"; out.properties_confirmNew = "Are you sure? Adding a password will change this pad's URL and remove its history. Users without the password will lose access to this pad";
out.properties_confirmChange = "Are you sure? Users without the new password will lose access to this pad"; out.properties_confirmChange = "Are you sure? Changing the password will remove its history. Users without the new password will lose access to this pad";
out.properties_passwordError = "An error occured while trying to change the password. Please try again."; out.properties_passwordError = "An error occured while trying to change the password. Please try again.";
out.properties_passwordWarning = "The password was successfully changed but we were unable to update your CryptDrive with the new data. You may have to remove the old version of the pad manually.<br>Press OK to reload and update your acces rights."; out.properties_passwordWarning = "The password was successfully changed but we were unable to update your CryptDrive with the new data. You may have to remove the old version of the pad manually.<br>Press OK to reload and update your acces rights.";
out.properties_passwordSuccess = "The password was successfully changed.<br>Press OK to reload and update your access rights."; out.properties_passwordSuccess = "The password was successfully changed.<br>Press OK to reload and update your access rights.";

@ -6,12 +6,11 @@
server { server {
listen 443 ssl http2; listen 443 ssl http2;
server_name your-main-domain.com your-sandbox-domain.com;
server_name cryptpad.fr www.cryptpad.fr beta.cryptpad.fr; ssl_certificate /home/cryptpad/.acme.sh/your-main-domain.com/fullchain.cer;
ssl_certificate_key /home/cryptpad/.acme.sh/your-main-domain.com/your-main-domain.com.key;
ssl_certificate /home/cryptpad/.acme.sh/alpha.cryptpad.fr/fullchain.cer; ssl_trusted_certificate /home/cryptpad/.acme.sh/your-main-domain.com/ca.cer;
ssl_certificate_key /home/cryptpad/.acme.sh/alpha.cryptpad.fr/alpha.cryptpad.fr.key;
ssl_trusted_certificate /home/cryptpad/.acme.sh/alpha.cryptpad.fr/ca.cer;
ssl_dhparam /etc/nginx/dhparam.pem; ssl_dhparam /etc/nginx/dhparam.pem;
ssl_session_timeout 5m; ssl_session_timeout 5m;
@ -27,6 +26,7 @@ server {
root /home/cryptpad/cryptpad; root /home/cryptpad/cryptpad;
index index.html; index index.html;
error_page 404 /customize.dist/404.html;
if ($args ~ ver=) { if ($args ~ ver=) {
set $cacheControl max-age=31536000; set $cacheControl max-age=31536000;
@ -34,25 +34,31 @@ server {
# Will not set any header if it is emptystring # Will not set any header if it is emptystring
add_header Cache-Control $cacheControl; add_header Cache-Control $cacheControl;
set $styleSrc "'unsafe-inline' 'self'"; set $styleSrc "'unsafe-inline' 'self' your-main-domain.com";
set $scriptSrc "'self'"; set $scriptSrc "'self' your-main-domain.com";
set $connectSrc "'self' wss://cryptpad.fr wss://api.cryptpad.fr"; set $connectSrc "'self' https://your-main-domain.com wss://your-main-domain.com https://api.your-main-domain.com wss://your-main-domain.com your-main-domain.com blob: your-main-domain.com";
set $fontSrc "'self'"; set $fontSrc "'self' data: your-main-domain.com";
set $imgSrc "data: * blob:"; set $imgSrc "data: * blob:";
set $frameSrc "'self' beta.cryptpad.fr"; set $frameSrc "'self' your-sandbox-domain.com blob:";
set $mediaSrc "* blob:";
if ($uri = /pad/inner.html) { set $childSrc "https://your-main-domain.com";
set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline'"; set $workerSrc "https://your-main-domain.com";
set $unsafe 0;
if ($uri = "/pad/inner.html") { set $unsafe 1; }
if ($host != sandbox.cryptpad.info) { set $unsafe 0; }
if ($unsafe) {
set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' new2.cryptpad.fr cryptpad.fr";
} }
add_header Content-Security-Policy "default-src 'none'; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc;"; add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc;";
location = /cryptpad_websocket {
location ^~ /cryptpad_websocket {
proxy_pass http://localhost:3000; proxy_pass http://localhost:3000;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# WebSocket support (nginx 1.4) # WebSocket support (nginx 1.4)
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
@ -84,11 +90,9 @@ server {
try_files $uri =404; try_files $uri =404;
} }
## TODO fix in the code so that we don't need this location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban)$ {
location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media)$ {
rewrite ^(.*)$ $1/ redirect; rewrite ^(.*)$ $1/ redirect;
} }
try_files /www/$uri /www/$uri/index.html /customize/$uri; try_files /www/$uri /www/$uri/index.html /customize/$uri;
} }

@ -1,8 +1,12 @@
{ {
"name": "cryptpad", "name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server", "description": "realtime collaborative visual editor with zero knowlege server",
"version": "2.3.0", "version": "2.4.0",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0+",
"repository": {
"type": "git",
"url": "git://github.com/xwiki-labs/cryptpad.git"
},
"dependencies": { "dependencies": {
"chainpad-server": "~2.1.0", "chainpad-server": "~2.1.0",
"express": "~4.16.0", "express": "~4.16.0",
@ -11,7 +15,6 @@
"pull-stream": "^3.6.1", "pull-stream": "^3.6.1",
"replify": "^1.2.0", "replify": "^1.2.0",
"saferphore": "0.0.1", "saferphore": "0.0.1",
"socket.io": "^2.1.1",
"sortify": "^1.0.4", "sortify": "^1.0.4",
"stream-to-pull-stream": "^1.7.2", "stream-to-pull-stream": "^1.7.2",
"tweetnacl": "~0.12.2", "tweetnacl": "~0.12.2",

@ -5,7 +5,7 @@ var Express = require('express');
var Http = require('http'); var Http = require('http');
var Https = require('https'); var Https = require('https');
var Fs = require('fs'); var Fs = require('fs');
var SocketIO = require('socket.io'); var WebSocketServer = require('ws').Server;
var NetfluxSrv = require('./node_modules/chainpad-server/NetfluxWebsocketSrv'); var NetfluxSrv = require('./node_modules/chainpad-server/NetfluxWebsocketSrv');
var Package = require('./package.json'); var Package = require('./package.json');
var Path = require("path"); var Path = require("path");
@ -249,10 +249,7 @@ var nt = nThen(function (w) {
console.log("setting up a new websocket server"); console.log("setting up a new websocket server");
wsConfig = { port: websocketPort}; wsConfig = { port: websocketPort};
} }
var wsSrv = new SocketIO(httpServer, { var wsSrv = new WebSocketServer(wsConfig);
path: config.websocketPath || '/cryptpad_websocket'
});
Storage.create(config, function (store) { Storage.create(config, function (store) {
NetfluxSrv.run(store, wsSrv, config, rpc); NetfluxSrv.run(store, wsSrv, config, rpc);
}); });

@ -119,5 +119,12 @@ define(function() {
// You can use config.afterLogin to import these values in the users' drive. // You can use config.afterLogin to import these values in the users' drive.
//config.disableProfile = true; //config.disableProfile = true;
// Disable the use of webworkers and sharedworkers in CryptPad.
// Workers allow us to run the websockets connection and open the user drive in a separate thread.
// SharedWorkers allow us to load only one websocket and one user drive for all the browser tabs,
// making it much faster to open new tabs.
// Warning: This is an experimental feature. It will be enabled by default once we're sure it's stable.
config.disableWorkers = true;
return config; return config;
}); });

@ -187,7 +187,7 @@ define([
if (!yes) { return; } if (!yes) { return; }
sframeChan.query("Q_PAD_PASSWORD_CHANGE", { sframeChan.query("Q_PAD_PASSWORD_CHANGE", {
href: data.href, href: data.href,
password: $(newPassword).val() password: $(newPassword).find('input').val()
}, function (err, data) { }, function (err, data) {
if (err || data.error) { if (err || data.error) {
return void UI.alert(Messages.properties_passwordError); return void UI.alert(Messages.properties_passwordError);

@ -954,7 +954,7 @@ define([
}, },
// Messaging // Messaging
Q_FRIEND_REQUEST: common.messaging.onFriendRequest.fire, Q_FRIEND_REQUEST: common.messaging.onFriendRequest.fire,
EV_FIREND_COMPLETE: common.messaging.onFriendComplete.fire, EV_FRIEND_COMPLETE: common.messaging.onFriendComplete.fire,
// Network // Network
NETWORK_DISCONNECT: common.onNetworkDisconnect.fire, NETWORK_DISCONNECT: common.onNetworkDisconnect.fire,
NETWORK_RECONNECT: function (data) { NETWORK_RECONNECT: function (data) {
@ -1076,7 +1076,6 @@ define([
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
var cfg = { var cfg = {
init: true, init: true,
//query: onMessage, // TODO temporary, will be replaced by a webworker channel
userHash: LocalStore.getUserHash(), userHash: LocalStore.getUserHash(),
anonHash: LocalStore.getFSHash(), anonHash: LocalStore.getFSHash(),
localToken: tryParsing(localStorage.getItem(Constants.tokenKey)), localToken: tryParsing(localStorage.getItem(Constants.tokenKey)),
@ -1093,11 +1092,32 @@ define([
var msgEv = Util.mkEvent(); var msgEv = Util.mkEvent();
var postMsg, worker; var postMsg, worker;
var noWorker = AppConfig.disableWorkers || false;
if (localStorage.CryptPad_noWorkers) {
noWorker = localStorage.CryptPad_noWorkers === '1';
console.error('WebWorker/SharedWorker state forced to ' + !noWorker);
}
Nthen(function (waitFor2) { Nthen(function (waitFor2) {
if (typeof(SharedWorker) !== "undefined") { if (Worker) {
var w = waitFor2();
worker = new Worker('/common/outer/testworker.js?' + urlArgs);
worker.onerror = function (errEv) {
errEv.preventDefault();
errEv.stopPropagation();
noWorker = true;
w();
};
worker.onmessage = function (ev) {
if (ev.data === "OK") {
w();
}
};
}
}).nThen(function (waitFor2) {
if (!noWorker && typeof(SharedWorker) !== "undefined") {
worker = new SharedWorker('/common/outer/sharedworker.js?' + urlArgs); worker = new SharedWorker('/common/outer/sharedworker.js?' + urlArgs);
worker.onerror = function (e) { worker.onerror = function (e) {
console.error(e); console.error(e.message);
}; };
worker.port.onmessage = function (ev) { worker.port.onmessage = function (ev) {
if (ev.data === "SW_READY") { if (ev.data === "SW_READY") {
@ -1113,7 +1133,7 @@ define([
window.addEventListener('beforeunload', function () { window.addEventListener('beforeunload', function () {
postMsg('CLOSE'); postMsg('CLOSE');
}); });
} else if (false && 'serviceWorker' in navigator) { } else if (false && !noWorker && 'serviceWorker' in navigator) {
var initializing = true; var initializing = true;
var stopWaiting = waitFor2(); // Call this function when we're ready var stopWaiting = waitFor2(); // Call this function when we're ready
@ -1163,8 +1183,11 @@ define([
window.addEventListener('beforeunload', function () { window.addEventListener('beforeunload', function () {
postMsg('CLOSE'); postMsg('CLOSE');
}); });
} else if (Worker) { } else if (!noWorker && Worker) {
worker = new Worker('/common/outer/webworker.js?' + urlArgs); worker = new Worker('/common/outer/webworker.js?' + urlArgs);
worker.onerror = function (e) {
console.error(e.message);
};
worker.onmessage = function (ev) { worker.onmessage = function (ev) {
msgEv.fire(ev); msgEv.fire(ev);
}; };
@ -1172,6 +1195,7 @@ define([
worker.postMessage(data); worker.postMessage(data);
}; };
} else { } else {
// Use the async store in the main thread if workers are not available
require(['/common/outer/noworker.js'], waitFor2(function (NoWorker) { require(['/common/outer/noworker.js'], waitFor2(function (NoWorker) {
NoWorker.onMessage(function (data) { NoWorker.onMessage(function (data) {
msgEv.fire({data: data}); msgEv.fire({data: data});

@ -894,7 +894,7 @@ define([
}; };
Store.messenger = { Store.messenger = {
getFriendList: function (data, cb) { getFriendList: function (clientId, data, cb) {
store.messenger.getFriendList(function (e, keys) { store.messenger.getFriendList(function (e, keys) {
cb({ cb({
error: e, error: e,
@ -902,7 +902,7 @@ define([
}); });
}); });
}, },
getMyInfo: function (data, cb) { getMyInfo: function (clientId, data, cb) {
store.messenger.getMyInfo(function (e, info) { store.messenger.getMyInfo(function (e, info) {
cb({ cb({
error: e, error: e,
@ -910,7 +910,7 @@ define([
}); });
}); });
}, },
getFriendInfo: function (data, cb) { getFriendInfo: function (clientId, data, cb) {
store.messenger.getFriendInfo(data, function (e, info) { store.messenger.getFriendInfo(data, function (e, info) {
cb({ cb({
error: e, error: e,
@ -918,7 +918,7 @@ define([
}); });
}); });
}, },
removeFriend: function (data, cb) { removeFriend: function (clientId, data, cb) {
store.messenger.removeFriend(data, function (e, info) { store.messenger.removeFriend(data, function (e, info) {
cb({ cb({
error: e, error: e,
@ -926,12 +926,12 @@ define([
}); });
}); });
}, },
openFriendChannel: function (data, cb) { openFriendChannel: function (clientId, data, cb) {
store.messenger.openFriendChannel(data, function (e) { store.messenger.openFriendChannel(data, function (e) {
cb({ error: e, }); cb({ error: e, });
}); });
}, },
getFriendStatus: function (data, cb) { getFriendStatus: function (clientId, data, cb) {
store.messenger.getStatus(data, function (e, online) { store.messenger.getStatus(data, function (e, online) {
cb({ cb({
error: e, error: e,
@ -939,7 +939,7 @@ define([
}); });
}); });
}, },
getMoreHistory: function (data, cb) { getMoreHistory: function (clientId, data, cb) {
store.messenger.getMoreHistory(data.curvePublic, data.sig, data.count, function (e, history) { store.messenger.getMoreHistory(data.curvePublic, data.sig, data.count, function (e, history) {
cb({ cb({
error: e, error: e,
@ -947,14 +947,14 @@ define([
}); });
}); });
}, },
sendMessage: function (data, cb) { sendMessage: function (clientId, data, cb) {
store.messenger.sendMessage(data.curvePublic, data.content, function (e) { store.messenger.sendMessage(data.curvePublic, data.content, function (e) {
cb({ cb({
error: e, error: e,
}); });
}); });
}, },
setChannelHead: function (data, cb) { setChannelHead: function (clientId, data, cb) {
store.messenger.setChannelHead(data.curvePublic, data.sig, function (e) { store.messenger.setChannelHead(data.curvePublic, data.sig, function (e) {
cb({ cb({
error: e error: e

@ -0,0 +1,4 @@
if (!self.crypto && !self.msCrypto) {
throw new Error("E_NOCRYPTO");
}
self.postMessage("OK");

@ -41,7 +41,6 @@ define([
if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); } if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); }
var data = exp.getFileData(id); var data = exp.getFileData(id);
data[attr] = clone(value); data[attr] = clone(value);
console.log(data);
cb(null); cb(null);
}; };
exp.getPadAttribute = function (href, attr, cb) { exp.getPadAttribute = function (href, attr, cb) {

@ -584,7 +584,9 @@ define([
onRemote: onRemote, onRemote: onRemote,
setHistory: setHistoryMode, setHistory: setHistoryMode,
applyVal: function (val) { applyVal: function (val) {
contentUpdate(JSON.parse(val) || ["BODY",{},[]]); contentUpdate(JSON.parse(val) || ["BODY",{},[]], function (h) {
return h;
});
}, },
$toolbar: $(toolbarContainer) $toolbar: $(toolbarContainer)
}; };

@ -79,7 +79,7 @@ define([
isComplete = data.isFull; isComplete = data.isFull;
Array.prototype.unshift.apply(allMessages, data.messages); // Destructive concat Array.prototype.unshift.apply(allMessages, data.messages); // Destructive concat
fillChainPad(realtime, allMessages); fillChainPad(realtime, allMessages);
cb (null, realtime); cb (null, realtime, data.isFull);
}); });
}; };
@ -142,7 +142,8 @@ define([
loading = true; loading = true;
$loadMore.removeClass('fa fa-ellipsis-h') $loadMore.removeClass('fa fa-ellipsis-h')
.append($('<span>', {'class': 'fa fa-refresh fa-spin fa-3x fa-fw'})); .append($('<span>', {'class': 'fa fa-refresh fa-spin fa-3x fa-fw'}));
loadMoreHistory(config, common, function (err, newRt) {
loadMoreHistory(config, common, function (err, newRt, isFull) {
if (err === 'EFULL') { if (err === 'EFULL') {
$loadMore.off('click').hide(); $loadMore.off('click').hide();
get(c); get(c);
@ -154,6 +155,10 @@ define([
update(newRt); update(newRt);
$loadMore.addClass('fa fa-ellipsis-h').html(''); $loadMore.addClass('fa fa-ellipsis-h').html('');
get(c); get(c);
if (isFull) {
$loadMore.off('click').hide();
$version.show();
}
if (cb) { cb(); } if (cb) { cb(); }
}); });
}; };
@ -181,7 +186,7 @@ define([
$hist.find('.cp-toolbar-history-fast-next').css('visibility', 'hidden'); $hist.find('.cp-toolbar-history-fast-next').css('visibility', 'hidden');
} }
var $pos = $hist.find('.cp-toolbar-history-pos'); var $pos = $hist.find('.cp-toolbar-history-pos');
var p = 100 * (1 - (-c / (states.length-1))); var p = 100 * (1 - (-c / (states.length-2)));
$pos.css('margin-left', p+'%'); $pos.css('margin-left', p+'%');
// Display the version when the full history is loaded // Display the version when the full history is loaded
@ -317,13 +322,17 @@ define([
}; };
// Load all the history messages into a new chainpad object // Load all the history messages into a new chainpad object
loadMoreHistory(config, common, function (err, newRt) { loadMoreHistory(config, common, function (err, newRt, isFull) {
History.readOnly = common.getMetadataMgr().getPrivateData().readOnly; History.readOnly = common.getMetadataMgr().getPrivateData().readOnly;
History.loading = false; History.loading = false;
if (err) { throw new Error(err); } if (err) { throw new Error(err); }
update(newRt); update(newRt);
c = states.length - 1; c = states.length - 1;
display(); display();
if (isFull) {
$loadMore.off('click').hide();
$version.show();
}
}); });
}; };

@ -51,7 +51,6 @@ define([
'cp-settings-thumbnails', 'cp-settings-thumbnails',
'cp-settings-userfeedback', 'cp-settings-userfeedback',
'cp-settings-change-password', 'cp-settings-change-password',
//'cp-settings-migrate',
'cp-settings-delete' 'cp-settings-delete'
], ],
'creation': [ 'creation': [

Loading…
Cancel
Save