View and restore the history of a pad

pull/1/head
yflory 8 years ago
parent 43c045721c
commit 92ea03d7d9

@ -422,6 +422,17 @@
display: inline-block; display: inline-block;
input { width: 50px; } input { width: 50px; }
} }
.gotoInput {
vertical-align: middle;
}
}
.cke_toolbox .cryptpad-toolbar-history {
input.gotoInput {
background: white;
height: 20px;
padding: 3px 3px;
border-radius: 5px;
}
} }
.cryptpad-spinner { .cryptpad-spinner {
height: 16px; height: 16px;

@ -488,6 +488,15 @@
.cryptpad-toolbar-history .goto input { .cryptpad-toolbar-history .goto input {
width: 50px; width: 50px;
} }
.cryptpad-toolbar-history .gotoInput {
vertical-align: middle;
}
.cke_toolbox .cryptpad-toolbar-history input.gotoInput {
background: white;
height: 20px;
padding: 3px 3px;
border-radius: 5px;
}
.cryptpad-spinner { .cryptpad-spinner {
height: 16px; height: 16px;
width: 16px; width: 16px;

@ -115,6 +115,17 @@ define(function () {
out.cancel = "Annuler"; out.cancel = "Annuler";
out.cancelButton = 'Annuler (Echap)'; out.cancelButton = 'Annuler (Echap)';
out.historyButton = "Afficher l'historique du document";
out.history_next = "Voir la version suivante";
out.history_prev = "Voir la version précédente";
out.history_goTo = "Voir la version sélectionnée";
out.history_close = "Retour";
out.history_closeTitle = "Fermer l'historique";
out.history_restore = "Restaurer";
out.history_restoreTitle = "Restaurer la version du document sélectionnée";
out.history_restorePrompt = "Êtes-vous sûr de vouloir remplacer la version actuelle du document par la version affichée ?";
out.history_restoreDone = "Document restauré";
// Polls // Polls
out.poll_title = "Sélecteur de date Zero Knowledge"; out.poll_title = "Sélecteur de date Zero Knowledge";

@ -117,6 +117,17 @@ define(function () {
out.cancel = "Cancel"; out.cancel = "Cancel";
out.cancelButton = 'Cancel (esc)'; out.cancelButton = 'Cancel (esc)';
out.historyButton = "Display the document history";
out.history_next = "Go to the next version";
out.history_prev = "Go to the previous version";
out.history_goTo = "Go to the selected version";
out.history_close = "Back";
out.history_closeTitle = "Close the history";
out.history_restore = "Restore";
out.history_restoreTitle = "Restore the selected version of the document";
out.history_restorePrompt = "Are you sure you want to replace the current version of the document by the displayed one?";
out.history_restoreDone = "Document restored";
// Polls // Polls
out.poll_title = "Zero Knowledge Date Picker"; out.poll_title = "Zero Knowledge Date Picker";

@ -54,6 +54,8 @@ define([
var defaultName = Cryptpad.getDefaultName(parsedHash); var defaultName = Cryptpad.getDefaultName(parsedHash);
var initialState = Messages.codeInitialState; var initialState = Messages.codeInitialState;
var isHistoryMode = false;
var editor = module.editor = CMeditor.fromTextArea($textarea[0], { var editor = module.editor = CMeditor.fromTextArea($textarea[0], {
lineNumbers: true, lineNumbers: true,
lineWrapping: true, lineWrapping: true,
@ -164,6 +166,14 @@ define([
var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); }; var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); };
var setHistory = function (bool, update) {
isHistoryMode = bool;
setEditable(!bool);
if (!bool && update) {
config.onRemote();
}
};
var isDefaultTitle = function () { var isDefaultTitle = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href); var parsed = Cryptpad.parsePadUrl(window.location.href);
return Cryptpad.isDefaultName(parsed, document.title); return Cryptpad.isDefaultName(parsed, document.title);
@ -191,6 +201,7 @@ define([
var onLocal = config.onLocal = function () { var onLocal = config.onLocal = function () {
if (initializing) { return; } if (initializing) { return; }
if (isHistoryMode) { return; }
if (readOnly) { return; } if (readOnly) { return; }
editor.save(); editor.save();
@ -372,7 +383,7 @@ define([
var onInit = config.onInit = function (info) { var onInit = config.onInit = function (info) {
userList = info.userList; userList = info.userList;
var config = { var configTb = {
displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'], displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'],
userData: userData, userData: userData,
readOnly: readOnly, readOnly: readOnly,
@ -388,8 +399,7 @@ define([
}, },
common: Cryptpad common: Cryptpad
}; };
if (readOnly) {delete config.changeNameID; } toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, userList, configTb);
toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside); var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username); var $userBlock = $bar.find('.' + Toolbar.constants.username);
@ -402,19 +412,36 @@ define([
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
} }
/* add an export button */ /* add a history button */
var $hist = Cryptpad.createButton(); var histConfig = {};
var historyRender = function () {}; histConfig.onRender = function (val) {
var historyClose = function () { if (typeof val === "undefined") { return; }
// TODO: enable onlocal, onremote... (or at least the display part) try {
var hjson = JSON.parse(val || '{}');
var remoteDoc = hjson.content;
editor.setValue(remoteDoc || '');
editor.save();
} catch (e) {
// Probably a parse error
console.error(e);
}
}; };
var historyTodo = function (hist) { histConfig.onClose = function () {
hist.display($bar, historyRender, historyClose); // Close button clicked
setHistory(false, true);
}; };
$hist.removeClass('fa-question').addClass('fa-history').click(function () { histConfig.onRevert = function () {
// TODO: disable onlocal, onremote... // Revert button clicked
Cryptpad.getHistory(historyTodo); setHistory(false, false);
}); config.onLocal();
config.onRemote();
};
histConfig.onReady = function () {
// Called when the history is loaded and the UI displayed
setHistory(true);
};
histConfig.$toolbar = $bar;
var $hist = Cryptpad.createButton('history', true, {histConfig: histConfig});
$rightside.append($hist); $rightside.append($hist);
/* save as template */ /* save as template */
@ -663,6 +690,7 @@ define([
var onRemote = config.onRemote = function () { var onRemote = config.onRemote = function () {
if (initializing) { return; } if (initializing) { return; }
if (isHistoryMode) { return; }
var scroll = editor.getScrollInfo(); var scroll = editor.getScrollInfo();
var oldDoc = canonicalize($textarea.val()); var oldDoc = canonicalize($textarea.val());

@ -9,6 +9,17 @@ define([
var History = {}; var History = {};
var getStates = function (rt) {
var states = [];
var b = rt.getAuthBlock();
if (b) { states.unshift(b.getContent().doc); }
while (b.getParent()) {
b = b.getParent();
states.unshift(b.getContent().doc);
}
return states;
};
/* TODO /* TODO
* Implement GET_FULL_HISTORY serverside * Implement GET_FULL_HISTORY serverside
* All the history messages should be ['FULL_HISTORY', wc.id, msg] * All the history messages should be ['FULL_HISTORY', wc.id, msg]
@ -23,22 +34,22 @@ define([
var wcId = common.hrefToHexChannelId(window.location.href); var wcId = common.hrefToHexChannelId(window.location.href);
var createRealtime = function(chan) { var createRealtime = function(chan) {
console.log(ChainPad);
return ChainPad.create({ return ChainPad.create({
userName: 'history', userName: 'history',
initialState: '', initialState: '',
transformFunction: JsonOT.validate, transformFunction: JsonOT.validate,
logLevel: 0 logLevel: 1,
noPrune: true
}); });
}; };
var realtime = createRealtime(); var realtime = createRealtime();
var secret = Cryptpad.getSecrets(); var secret = common.getSecrets();
var crypto = Crypto.createEncryptor(secret.keys); var crypto = Crypto.createEncryptor(secret.keys);
var to = window.setTimeout(function () { var to = window.setTimeout(function () {
cb('[GET_FULL_HISTORY_TIMEOUT]'); cb('[GET_FULL_HISTORY_TIMEOUT]');
}, 3000); }, 30000);
var parse = function (msg) { var parse = function (msg) {
try { try {
@ -50,104 +61,169 @@ define([
var onMsg = function (msg) { var onMsg = function (msg) {
var parsed = parse(msg); var parsed = parse(msg);
if (parsed[0] === 'FULL_HISTORY_END') { if (parsed[0] === 'FULL_HISTORY_END') {
console.log('END');
window.clearTimeout(to); window.clearTimeout(to);
cb(null, realtime); cb(null, realtime);
return; return;
} }
if (parsed[0] !== 'FULL_HISTORY') { return; } if (parsed[0] !== 'FULL_HISTORY') { return; }
var msg = parsed[1]; msg = parsed[1][4];
if (msg) {
msg = msg.replace(/^cp\|/, '');
var decryptedMsg = crypto.decrypt(msg, secret.keys.validateKey); var decryptedMsg = crypto.decrypt(msg, secret.keys.validateKey);
realtime.message(decryptedMsg); realtime.message(decryptedMsg);
}
}; };
network.on('message', function (msg, sender) { network.on('message', function (msg, sender) {
onMsg(msg); onMsg(msg);
}); });
network.sendto(hkn, JSON.stringify(['GET_FULL_HISTORY', wcId])); network.sendto(hkn, JSON.stringify(['GET_FULL_HISTORY', wcId, secret.keys.validateKey]));
}; };
var create = History.create = function (common, cb) { var create = History.create = function (common, config) {
var exp = {}; if (!config.$toolbar) { return void console.error("config.$toolbar is undefined");}
var $toolbar = config.$toolbar;
var noFunc = function () {};
var render = config.onRender || noFunc;
var onClose = config.onClose || noFunc;
var onRevert = config.onRevert || noFunc;
var onReady = config.onReady || noFunc;
var Messages = common.Messages;
var states = exp.states = ['a', 'b', 'c']; var realtime;
var c = exp.current = states.length - 1;
console.log(c); var states = []; //getStates(rt); //['a', 'b', 'c'];
var c = states.length - 1;
var $hist = $toolbar.find('.cryptpad-toolbar-history');
var $left = $toolbar.find('.cryptpad-toolbar-leftside');
var $right = $toolbar.find('.cryptpad-toolbar-rightside');
var onUpdate; var onUpdate;
var update = exp.update = function () { var update = function () {
states = []; if (!realtime) { return []; }
states = getStates(realtime);
if (typeof onUpdate === "function") { onUpdate(); } if (typeof onUpdate === "function") { onUpdate(); }
return states; return states;
}; };
var get = exp.get = function (i) { // Get the content of the selected version, and change the version number
var get = function (i) {
i = parseInt(i); i = parseInt(i);
console.log('getting', i); if (isNaN(i)) { return; }
if (typeof(i) !== "number" || i < 0 || i > states.length - 1) { return; } if (i < 0) { i = 0; }
var hash = states[i]; if (i > states.length - 1) { i = states.length - 1; }
var val = states[i];
c = i; c = i;
if (typeof onUpdate === "function") { onUpdate(); } if (typeof onUpdate === "function") { onUpdate(); }
return ''; $hist.find('.next, .previous').show();
if (c === states.length - 1) { $hist.find('.next').hide(); }
if (c === 0) { $hist.find('.previous').hide(); }
return val || '';
}; };
var getNext = exp.getNext = function () { var getNext = function (step) {
if (c < states.length - 1) { return get(++c); } return typeof step === "number" ? get(c + step) : get(c + 1);
}; };
var getPrevious = exp.getPrevious = function () { var getPrevious = function (step) {
if (c > 0) { return get(--c); } return typeof step === "number" ? get(c - step) : get(c - 1);
}; };
var display = exp.display = function ($toolbar, render, onClose) { // Create the history toolbar
var $hist = $toolbar.find('.cryptpad-toolbar-history').html('').show(); var display = function () {
var $left = $toolbar.find('.cryptpad-toolbar-leftside').hide(); $hist.html('').show();
var $right = $toolbar.find('.cryptpad-toolbar-rightside').hide(); $left.hide();
$right.hide();
var $prev =$('<button>', {'class': 'previous'}).text('<<').appendTo($hist); var $prev =$('<button>', {
var $next = $('<button>', {'class': 'next'}).text('>>').appendTo($hist); 'class': 'previous fa fa-step-backward',
title: Messages.history_prev
}).appendTo($hist);
var $next = $('<button>', {
'class': 'next fa fa-step-forward',
title: Messages.history_next
}).appendTo($hist);
var $nav = $('<div>', {'class': 'goto'}).appendTo($hist); var $nav = $('<div>', {'class': 'goto'}).appendTo($hist);
var $cur = $('<input>', { var $cur = $('<input>', {
'class' : 'gotoInput',
'type' : 'number', 'type' : 'number',
'min' : '1', 'min' : '1',
'max' : states.length 'max' : states.length
}).val(c + 1).appendTo($nav); }).val(c + 1).appendTo($nav);
var $label = $('<label>').text(' / '+ states.length).appendTo($nav); var $label = $('<label>').text(' / '+ states.length).appendTo($nav);
var $goTo = $('<button>').text('V').appendTo($nav); var $goTo = $('<button>', {
'class': 'fa fa-check',
'title': Messages.history_goTo
}).appendTo($nav);
$('<br>').appendTo($nav); $('<br>').appendTo($nav);
var $rev = $('<button>', {'class':'revertHistory'}).text('TODO: revert').appendTo($nav); var $rev = $('<button>', {
var $close = $('<button>', {'class':'closeHistory'}).text('TODO: close').appendTo($nav); 'class':'revertHistory',
title: Messages.history_restoreTitle
}).text(Messages.history_restore).appendTo($nav);
var $close = $('<button>', {
'class':'closeHistory',
title: Messages.history_closeTitle
}).text(Messages.history_close).appendTo($nav);
onUpdate = function () { onUpdate = function () {
$cur.attr('max', exp.states.length); $cur.attr('max', states.length);
$cur.val(c+1); $cur.val(c+1);
$label.text(' / ' + states.length);
}; };
var toRender = function (getter) { var close = function () {
return function () { render(getter()) }; $hist.hide();
$left.show();
$right.show();
}; };
$prev.click(toRender(getPrevious)); // Buttons actions
$next.click(toRender(getNext)); $prev.click(function () { render(getPrevious()); });
$goTo.click(function () { $next.click(function () { render(getNext()); });
render( get($cur.val() - 1) ) $goTo.click(function () { render( get($cur.val() - 1) ); });
$cur.keydown(function (e) {
var p = function () { e.preventDefault(); };
if (e.which === 13) { p(); return render( get($cur.val() - 1) ); } // Enter
if ([37, 40].indexOf(e.which) >= 0) { p(); return render(getPrevious()); } // Left
if ([38, 39].indexOf(e.which) >= 0) { p(); return render(getNext()); } // Right
if (e.which === 33) { p(); return render(getNext(10)); } // PageUp
if (e.which === 34) { p(); return render(getPrevious(10)); } // PageUp
if (e.which === 27) { p(); $close.click(); }
}).focus();
$cur.on('change', function () {
$goTo.click();
}); });
$close.click(function () { $close.click(function () {
$hist.hide(); states = [];
$left.show(); close();
$right.show();
onClose(); onClose();
}); });
$rev.click(function () {
common.confirm(Messages.history_restorePrompt, function (yes) {
if (!yes) { return; }
close();
onRevert();
common.log(Messages.history_restoreDone);
});
});
// Display the latest content
render(get(c)); render(get(c));
}; };
// Load all the history messages into a new chainpad object
loadHistory(common, function (err, newRt) { loadHistory(common, function (err, newRt) {
if (err) { throw new Error(err); } if (err) { throw new Error(err); }
realtime = exp.realtime = newRt; realtime = newRt;
cb(exp); update();
c = states.length - 1;
display();
onReady();
}); });
}; };

@ -83,9 +83,7 @@ define([
common.findStronger = Hash.findStronger; common.findStronger = Hash.findStronger;
// History // History
common.getHistory = function (cb) { common.getHistory = function (config) { return History.create(common, config); };
return History.create(common, cb);
};
var getStore = common.getStore = function () { var getStore = common.getStore = function () {
if (store) { return store; } if (store) { return store; }
@ -808,6 +806,18 @@ define([
style: 'font:'+size+' FontAwesome' style: 'font:'+size+' FontAwesome'
}); });
break; break;
case 'history':
button = $('<button>', {
title: Messages.historyButton,
'class': "fa fa-history",
style: 'font:'+size+' FontAwesome'
});
if (data.histConfig) {
button.click(function () {
common.getHistory(data.histConfig);
});
};
break;
default: default:
button = $('<button>', { button = $('<button>', {
'class': "fa fa-question", 'class': "fa fa-question",

@ -110,6 +110,8 @@ define([
var parsedHash = Cryptpad.parsePadUrl(window.location.href); var parsedHash = Cryptpad.parsePadUrl(window.location.href);
var defaultName = Cryptpad.getDefaultName(parsedHash); var defaultName = Cryptpad.getDefaultName(parsedHash);
var isHistoryMode = false;
if (readOnly) { if (readOnly) {
$('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox > .cke_toolbox_main').hide(); $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox > .cke_toolbox_main').hide();
} }
@ -413,6 +415,14 @@ define([
} }
}; };
var setHistory = function (bool, update) {
isHistoryMode = bool;
setEditable(!bool);
if (!bool && update) {
realtimeOptions.onRemote();
}
};
var updateTitle = function (newTitle) { var updateTitle = function (newTitle) {
if (newTitle === document.title) { return; } if (newTitle === document.title) { return; }
// Change the title now, and set it back to the old value if there is an error // Change the title now, and set it back to the old value if there is an error
@ -477,6 +487,7 @@ define([
var onRemote = realtimeOptions.onRemote = function () { var onRemote = realtimeOptions.onRemote = function () {
if (initializing) { return; } if (initializing) { return; }
if (isHistoryMode) { return; }
var oldShjson = stringifyDOM(inner); var oldShjson = stringifyDOM(inner);
@ -568,7 +579,7 @@ define([
var onInit = realtimeOptions.onInit = function (info) { var onInit = realtimeOptions.onInit = function (info) {
userList = info.userList; userList = info.userList;
var config = { var configTb = {
displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'], displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'],
userData: userData, userData: userData,
readOnly: readOnly, readOnly: readOnly,
@ -584,8 +595,7 @@ define([
}, },
common: Cryptpad common: Cryptpad
}; };
if (readOnly) {delete config.changeNameID; } toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, userList, configTb);
toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside); var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username); var $userBlock = $bar.find('.' + Toolbar.constants.username);
@ -617,6 +627,39 @@ define([
$rightside.append($collapse); $rightside.append($collapse);
} }
/* add a history button */
var histConfig = {};
histConfig.onRender = function (val) {
if (typeof val === "undefined") { return; }
try {
applyHjson(val || '');
/*var hjson = JSON.parse(val || '{}'); // TODO
var remoteDoc = hjson.content;
editor.setValue(remoteDoc || ''); // TODO
editor.save(); // TODO*/
} catch (e) {
// Probably a parse error
console.error(e);
}
};
histConfig.onClose = function () {
// Close button clicked
setHistory(false, true);
};
histConfig.onRevert = function () {
// Revert button clicked
setHistory(false, false);
realtimeOptions.onLocal();
realtimeOptions.onRemote();
};
histConfig.onReady = function () {
// Called when the history is loaded and the UI displayed
setHistory(true);
};
histConfig.$toolbar = $bar;
var $hist = Cryptpad.createButton('history', true, {histConfig: histConfig});
$rightside.append($hist);
/* save as template */ /* save as template */
if (!Cryptpad.isTemplate(window.location.href)) { if (!Cryptpad.isTemplate(window.location.href)) {
var templateObj = { var templateObj = {
@ -767,6 +810,7 @@ define([
var onLocal = realtimeOptions.onLocal = function () { var onLocal = realtimeOptions.onLocal = function () {
if (initializing) { return; } if (initializing) { return; }
if (isHistoryMode) { return; }
if (readOnly) { return; } if (readOnly) { return; }
// stringify the json and send it into chainpad // stringify the json and send it into chainpad

@ -74,6 +74,8 @@ define([
var defaultName = Cryptpad.getDefaultName(parsedHash); var defaultName = Cryptpad.getDefaultName(parsedHash);
var initialState = Messages.slideInitialState; var initialState = Messages.slideInitialState;
var isHistoryMode = false;
var editor = module.editor = CMeditor.fromTextArea($textarea[0], { var editor = module.editor = CMeditor.fromTextArea($textarea[0], {
lineNumbers: true, lineNumbers: true,
lineWrapping: true, lineWrapping: true,
@ -214,6 +216,14 @@ define([
var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); }; var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); };
var setHistory = function (bool, update) {
isHistoryMode = bool;
setEditable(!bool);
if (!bool && update) {
config.onRemote();
}
};
var isDefaultTitle = function () { var isDefaultTitle = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href); var parsed = Cryptpad.parsePadUrl(window.location.href);
return Cryptpad.isDefaultName(parsed, APP.title); return Cryptpad.isDefaultName(parsed, APP.title);
@ -245,6 +255,7 @@ define([
var onLocal = config.onLocal = function () { var onLocal = config.onLocal = function () {
if (initializing) { return; } if (initializing) { return; }
if (isHistoryMode) { return; }
if (readOnly) { return; } if (readOnly) { return; }
editor.save(); editor.save();
@ -503,7 +514,7 @@ define([
var onInit = config.onInit = function (info) { var onInit = config.onInit = function (info) {
userList = info.userList; userList = info.userList;
var config = { var configTb = {
displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'], displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'],
userData: userData, userData: userData,
readOnly: readOnly, readOnly: readOnly,
@ -519,8 +530,7 @@ define([
}, },
common: Cryptpad common: Cryptpad
}; };
if (readOnly) {delete config.changeNameID; } toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, configTb);
toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside); var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username); var $userBlock = $bar.find('.' + Toolbar.constants.username);
@ -533,6 +543,38 @@ define([
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
} }
/* add a history button */
var histConfig = {};
histConfig.onRender = function (val) {
if (typeof val === "undefined") { return; }
try {
var hjson = JSON.parse(val || '{}');
var remoteDoc = hjson.content;
editor.setValue(remoteDoc || '');
editor.save();
} catch (e) {
// Probably a parse error
console.error(e);
}
};
histConfig.onClose = function () {
// Close button clicked
setHistory(false, true);
};
histConfig.onRevert = function () {
// Revert button clicked
setHistory(false, false);
config.onLocal();
config.onRemote();
};
histConfig.onReady = function () {
// Called when the history is loaded and the UI displayed
setHistory(true);
};
histConfig.$toolbar = $bar;
var $hist = Cryptpad.createButton('history', true, {histConfig: histConfig});
$rightside.append($hist);
/* save as template */ /* save as template */
if (!Cryptpad.isTemplate(window.location.href)) { if (!Cryptpad.isTemplate(window.location.href)) {
var templateObj = { var templateObj = {
@ -842,6 +884,7 @@ define([
var onRemote = config.onRemote = function () { var onRemote = config.onRemote = function () {
if (initializing) { return; } if (initializing) { return; }
if (isHistoryMode) { return; }
var scroll = editor.getScrollInfo(); var scroll = editor.getScrollInfo();
var oldDoc = canonicalize($textarea.val()); var oldDoc = canonicalize($textarea.val());

Loading…
Cancel
Save