Realtime spreadsheets
parent
c5f554fe7b
commit
8dbeee1af9
|
@ -56,10 +56,13 @@ define([
|
|||
var toolbar;
|
||||
|
||||
var andThen = function (common) {
|
||||
var sframeChan = common.getSframeChannel();
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
var readOnly = false;
|
||||
var locked = false;
|
||||
var config = {};
|
||||
var hashes = [];
|
||||
var channel;
|
||||
|
||||
var getFileType = function () {
|
||||
var type = common.getMetadataMgr().getPrivateData().ooType;
|
||||
|
@ -85,17 +88,86 @@ define([
|
|||
return file;
|
||||
};
|
||||
|
||||
var openRtChannel = function (data) {
|
||||
// XXX
|
||||
var channel = Hash.createChannelId();
|
||||
ctx.sframeChan.query('Q_OO_OPENCHANNEL', {
|
||||
var now = function () { return +new Date(); };
|
||||
|
||||
var getLastCp = function () {
|
||||
if (!hashes || !hashes.length) { return; }
|
||||
var last = hashes.slice().pop();
|
||||
var parsed = Hash.parsePadUrl(last);
|
||||
var secret = Hash.getSecrets('file', parsed.hash);
|
||||
if (!secret || !secret.channel) { return; }
|
||||
return 'cp|' + secret.channel.slice(0,8);
|
||||
};
|
||||
|
||||
var rtChannel = {
|
||||
ready: false,
|
||||
readyCb: undefined,
|
||||
sendCmd: function (data, cb) {
|
||||
sframeChan.query('Q_OO_COMMAND', data, cb);
|
||||
},
|
||||
sendMsg: function (msg, cp, cb) {
|
||||
rtChannel.sendCmd({
|
||||
cmd: 'SEND_MESSAGE',
|
||||
data: {
|
||||
msg: msg,
|
||||
isCp: cp
|
||||
}
|
||||
}, cb);
|
||||
},
|
||||
};
|
||||
|
||||
var ooChannel = {
|
||||
ready: false,
|
||||
queue: [],
|
||||
send: function () {}
|
||||
};
|
||||
|
||||
var openRtChannel = function (cb) {
|
||||
if (rtChannel.ready) { return; }
|
||||
var chan = channel || Hash.createChannelId();
|
||||
if (!channel) {
|
||||
channel = chan;
|
||||
APP.onLocal();
|
||||
}
|
||||
sframeChan.query('Q_OO_OPENCHANNEL', {
|
||||
channel: channel,
|
||||
lastCp: data.lastCp
|
||||
lastCp: getLastCp()
|
||||
}, function (err, obj) {
|
||||
if (err || (obj && obj.error)) { console.error(err || (obj && obj.error)); }
|
||||
});
|
||||
sframeChan.on('EV_OO_EVENT', function (data) {
|
||||
switch (data.ev) {
|
||||
case 'READY':
|
||||
rtChannel.ready = true;
|
||||
break;
|
||||
case 'MESSAGE':
|
||||
if (ooChannel.ready) {
|
||||
ooChannel.send(data.data);
|
||||
} else {
|
||||
ooChannel.queue.push(data.data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
cb();
|
||||
};
|
||||
|
||||
var parseChanges = function (changes) {
|
||||
try {
|
||||
changes = JSON.parse(changes);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
return changes.map(function (change) {
|
||||
return {
|
||||
docid: "fresh",
|
||||
change: '"' + change + '"',
|
||||
time: now(),
|
||||
user: "test", // XXX get username
|
||||
useridoriginal: "test" // get user id from worker?
|
||||
};
|
||||
});
|
||||
};
|
||||
var mkChannel = function () {
|
||||
var msgEv = Util.mkEvent();
|
||||
var iframe = $('#cp-app-oo-container > iframe')[0].contentWindow;
|
||||
|
@ -108,11 +180,83 @@ define([
|
|||
};
|
||||
Channel.create(msgEv, postMsg, function (chan) {
|
||||
APP.chan = chan;
|
||||
chan.on('CMDFROMOO', function (data) {
|
||||
console.log('command from oo', data);
|
||||
setTimeout(function () {
|
||||
chan.event('RTMSG', 'Pewpewpew');
|
||||
}, 2000);
|
||||
|
||||
var send = ooChannel.send = function (obj) {
|
||||
chan.event('CMD', obj);
|
||||
};
|
||||
|
||||
chan.on('CMD', function (obj) {
|
||||
var msg, msg2;
|
||||
switch (obj.type) {
|
||||
case "auth":
|
||||
ooChannel.ready = true;
|
||||
send({
|
||||
type: "auth",
|
||||
result: 1,
|
||||
sessionId: "08e77705-dc5c-477d-b73a-b1a7cbca1e9b",
|
||||
participants: [{
|
||||
id: "myid1",
|
||||
idOriginal: "myid",
|
||||
username: "User",
|
||||
indexUser: 1,
|
||||
view: false
|
||||
}],
|
||||
locks: [],
|
||||
changes: [],
|
||||
changesIndex: 0,
|
||||
indexUser: 1,
|
||||
"g_cAscSpellCheckUrl": "/spellchecker"
|
||||
});
|
||||
send({
|
||||
type: "documentOpen",
|
||||
data: {"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
|
||||
});
|
||||
setTimeout(function () {
|
||||
if (ooChannel.queue) {
|
||||
ooChannel.queue.forEach(function (msg) {
|
||||
send(msg);
|
||||
});
|
||||
}
|
||||
}, 2000);
|
||||
break;
|
||||
case "isSaveLock":
|
||||
msg = {
|
||||
type: "saveLock",
|
||||
saveLock: false
|
||||
}
|
||||
send(msg);
|
||||
break;
|
||||
case "getLock":
|
||||
msg = {
|
||||
type: "getLock",
|
||||
locks: [{
|
||||
time: now(),
|
||||
user: "myid1",
|
||||
block: obj.block && obj.block[0],
|
||||
sessionId: "08e77705-dc5c-477d-b73a-b1a7cbca1e9b"
|
||||
}]
|
||||
}
|
||||
send(msg);
|
||||
break;
|
||||
case "getMessages":
|
||||
send({ type: "message" });
|
||||
break;
|
||||
case "saveChanges":
|
||||
// XXX lock
|
||||
send({
|
||||
type: "unSaveLock",
|
||||
index: -1,
|
||||
});
|
||||
rtChannel.sendMsg({
|
||||
type: "saveChanges",
|
||||
changes: parseChanges(obj.changes),
|
||||
changesIndex: 2,
|
||||
locks: [], // XXX take from userdoc?
|
||||
excelAdditionalInfo: null
|
||||
}, null, function () {
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -120,7 +264,7 @@ define([
|
|||
var startOO = function (blob, file) {
|
||||
if (APP.ooconfig) { return void console.error('already started'); }
|
||||
var url = URL.createObjectURL(blob);
|
||||
var lock = locked !== common.getMetadataMgr().getNetfluxId() ||
|
||||
var lock = /*locked !== common.getMetadataMgr().getNetfluxId() ||*/
|
||||
!common.isLoggedIn();
|
||||
|
||||
// Config
|
||||
|
@ -144,20 +288,13 @@ define([
|
|||
}
|
||||
},
|
||||
"user": {
|
||||
"id": "", //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
||||
"name": "", //"John Smith"
|
||||
"id": "myid", //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
||||
"name": "User", //"John Smith"
|
||||
},
|
||||
"mode": readOnly || lock ? "view" : "edit"
|
||||
},
|
||||
"events": {
|
||||
"onDocumentStateChange": function (evt) {
|
||||
if (evt.data) {
|
||||
console.log('in change (local)');
|
||||
return;
|
||||
}
|
||||
console.log("in change (remote)");
|
||||
},
|
||||
"onReady": function(/*evt*/) {
|
||||
"onAppReady": function(/*evt*/) {
|
||||
var $tb = $('iframe[name="frameEditor"]').contents().find('head');
|
||||
var css = '#id-toolbar-full .toolbar-group:nth-child(2), #id-toolbar-full .separator:nth-child(3) { display: none; }' +
|
||||
'#fm-btn-save { display: none !important; }' +
|
||||
|
@ -169,8 +306,6 @@ define([
|
|||
});
|
||||
}
|
||||
},
|
||||
"onAppReady": function(/*evt*/) { console.log("in onAppReady"); },
|
||||
"onDownloadAs": function (evt) { console.log("in onDownloadAs", evt); }
|
||||
}
|
||||
};
|
||||
window.onbeforeunload = function () {
|
||||
|
@ -202,8 +337,10 @@ define([
|
|||
return void UI.alert(Messages.oo_saveError);
|
||||
}
|
||||
hashes.push(data.url);
|
||||
UI.log(Messages.saved);
|
||||
APP.onLocal();
|
||||
rtChannel.sendMsg(null, getLastCp(), function () {
|
||||
UI.log(Messages.saved);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -248,7 +385,6 @@ define([
|
|||
var loadDocument = function (newPad) {
|
||||
var type = common.getMetadataMgr().getPrivateData().ooType;
|
||||
var file = getFileType();
|
||||
console.log(newPad);
|
||||
if (!newPad) {
|
||||
return void loadLastDocument();
|
||||
}
|
||||
|
@ -274,7 +410,6 @@ define([
|
|||
var $bar = $('#cp-toolbar');
|
||||
var Title;
|
||||
var cpNfInner;
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
|
||||
config = {
|
||||
patchTransformer: ChainPad.NaiveJSONTransformer,
|
||||
|
@ -298,8 +433,9 @@ define([
|
|||
var stringifyInner = function () {
|
||||
var obj = {
|
||||
content: {
|
||||
channel: channel,
|
||||
hashes: hashes || [],
|
||||
locked: locked
|
||||
//locked: locked
|
||||
},
|
||||
metadata: metadataMgr.getMetadataLazy()
|
||||
};
|
||||
|
@ -385,7 +521,8 @@ define([
|
|||
throw new Error(errorText);
|
||||
}
|
||||
hashes = hjson.content && hjson.content.hashes;
|
||||
locked = hjson.content && hjson.content.locked;
|
||||
//locked = hjson.content && hjson.content.locked;
|
||||
channel = hjson.content && hjson.content.channel;
|
||||
newDoc = !hashes || hashes.length === 0;
|
||||
} else {
|
||||
Title.updateTitle(Title.defaultTitle);
|
||||
|
@ -393,7 +530,7 @@ define([
|
|||
|
||||
if (!readOnly) {
|
||||
// Check if the editor has left
|
||||
var me = common.getMetadataMgr().getNetfluxId();
|
||||
/*var me = common.getMetadataMgr().getNetfluxId();
|
||||
var members = common.getMetadataMgr().getChannelMembers();
|
||||
if (locked) {
|
||||
if (members.indexOf(locked) === -1) {
|
||||
|
@ -409,15 +546,17 @@ define([
|
|||
UI.alert(Messages.oo_locked + Messages.oo_locked_unregistered);
|
||||
} else if (locked !== me) {
|
||||
UI.alert(Messages.oo_locked + Messages.oo_locked_edited);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
openRtChannel(function () {
|
||||
loadDocument(newDoc);
|
||||
|
||||
loadDocument(newDoc);
|
||||
initializing = false;
|
||||
setEditable(!readOnly);
|
||||
UI.removeLoadingScreen();
|
||||
});
|
||||
|
||||
initializing = false;
|
||||
setEditable(!readOnly);
|
||||
UI.removeLoadingScreen();
|
||||
};
|
||||
|
||||
var reloadDisplayed = false;
|
||||
|
@ -428,6 +567,7 @@ define([
|
|||
if (json.metadata) {
|
||||
metadataMgr.updateMetadata(json.metadata);
|
||||
}
|
||||
/*
|
||||
var newHashes = (json.content && json.content.hashes) || [];
|
||||
if (newHashes.length !== hashes.length ||
|
||||
stringify(newHashes) !== stringify(hashes)) {
|
||||
|
@ -440,6 +580,7 @@ define([
|
|||
common.gotoURL();
|
||||
});
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
config.onAbort = function () {
|
||||
|
|
|
@ -56,6 +56,7 @@ define([
|
|||
});
|
||||
});
|
||||
sframeChan.on('Q_OO_OPENCHANNEL', function (data, cb) {
|
||||
console.log(data);
|
||||
Cryptpad.onlyoffice.execCommand({
|
||||
cmd: 'OPEN_CHANNEL',
|
||||
data: {
|
||||
|
@ -69,14 +70,22 @@ define([
|
|||
}, cb);
|
||||
});
|
||||
sframeChan.on('Q_OO_COMMAND', function (obj, cb) {
|
||||
if (obj.cmd === 'SEND_MESSAGE' && !obj.data.isCp) {
|
||||
obj.data.msg = crypto.encrypt(obj.data.msg);
|
||||
if (obj.cmd === 'SEND_MESSAGE') {
|
||||
if (obj.data.isCp) {
|
||||
obj.data.isCp += '|' + crypto.encrypt('cp');
|
||||
} else {
|
||||
obj.data.msg = crypto.encrypt(JSON.stringify(obj.data.msg));
|
||||
}
|
||||
}
|
||||
Cryptpad.onlyoffice.execCommand(obj, cb);
|
||||
});
|
||||
Cryptpad.onlyoffice.onEvent.reg(function (obj) {
|
||||
if (obj.ev === 'MESSAGE') {
|
||||
obj.data = crypto.decrypt(obj.data, Utils.secret.keys.validateKeys);
|
||||
try {
|
||||
obj.data = JSON.parse(crypto.decrypt(obj.data, Utils.secret.keys.validateKey));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
sframeChan.event('EV_OO_EVENT', obj);
|
||||
});
|
||||
|
|
|
@ -4206,8 +4206,8 @@ AscBrowser.convertToRetinaValue = function(value, isScale)
|
|||
light: false,
|
||||
trial: false,
|
||||
rights: 1,
|
||||
buildVersion: "4.3.3",
|
||||
buildNumber: 4,
|
||||
buildVersion: "5.2.6",
|
||||
buildNumber: 5,
|
||||
branding: false
|
||||
}
|
||||
};
|
||||
|
@ -4228,12 +4228,8 @@ AscBrowser.convertToRetinaValue = function(value, isScale)
|
|||
p.postMessage(data, '*');
|
||||
};
|
||||
Channel.create(msgEv, postMsg, function (chan) {
|
||||
console.log('created', chan);
|
||||
channel = chan;
|
||||
send(license);
|
||||
chan.on('RTMSG', function (data) {
|
||||
console.log('receiving RTMSG', data);
|
||||
});
|
||||
chan.on('CMD', function (obj) {
|
||||
send(obj);
|
||||
});
|
||||
|
@ -4258,33 +4254,9 @@ AscBrowser.convertToRetinaValue = function(value, isScale)
|
|||
console.error(e);
|
||||
return;
|
||||
}
|
||||
var msg, msg2;
|
||||
switch (obj.type) {
|
||||
case 'auth':
|
||||
msg = {
|
||||
"type":"auth",
|
||||
"result":1,
|
||||
"sessionId":"08e77705-dc5c-477d-b73a-b1a7cbca1e9b",
|
||||
"sessionTimeConnect":+new Date(),
|
||||
"participants":[]
|
||||
};
|
||||
msg2 = {
|
||||
"type":"documentOpen",
|
||||
"data":{"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
|
||||
};
|
||||
send(msg);
|
||||
send(msg2);
|
||||
if (channel) { channel.event('CMDFROMOO', 'Hey'); }
|
||||
break;
|
||||
case 'getMessages':
|
||||
msg = {};
|
||||
break;
|
||||
default:
|
||||
if (channel) {
|
||||
channel.event('CMD', obj);
|
||||
}
|
||||
break
|
||||
}
|
||||
if (channel) {
|
||||
channel.event('CMD', obj);
|
||||
}
|
||||
};
|
||||
|
||||
sockjs.onmessage = function (e) {
|
||||
|
|
|
@ -932,7 +932,7 @@ define([
|
|||
Store.onlyoffice = {
|
||||
execCommand: function (clientId, data, cb) {
|
||||
if (!store.onlyoffice) { return void cb({error: 'OnlyOffice is disabled'}); }
|
||||
store.onlyoffice.execCommand(data, cb);
|
||||
store.onlyoffice.execCommand(clientId, data, cb);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@ define([
|
|||
if (!c.id) { c.id = chan.wc.myID + '-' + client; }
|
||||
|
||||
/// XXX send chan.history to client
|
||||
chan.history.forEach(function (msg) {
|
||||
ctx.emit('MESSAGE', msg, [client]);
|
||||
});
|
||||
|
||||
// ==> And push the new tab to the list
|
||||
chan.clients.push(client);
|
||||
|
@ -38,7 +41,9 @@ define([
|
|||
|
||||
var onOpen = function (wc) {
|
||||
|
||||
ctx.channels[channel] = ctx.channels[channel] || {};
|
||||
ctx.channels[channel] = ctx.channels[channel] || {
|
||||
history: []
|
||||
};
|
||||
|
||||
chan = ctx.channels[channel];
|
||||
|
||||
|
@ -61,15 +66,24 @@ define([
|
|||
wc.on('leave', function (peer) {
|
||||
// XXX
|
||||
});
|
||||
wc.on('message', function (cryptMsg) {
|
||||
ctx.emit('MESSAGE', cryptMsg, chan.clients);
|
||||
wc.on('message', function (msg) {
|
||||
if (/^cp\|/.test(msg)) {
|
||||
chan.history = [];
|
||||
} else {
|
||||
chan.history.push(msg);
|
||||
}
|
||||
ctx.emit('MESSAGE', msg, chan.clients);
|
||||
});
|
||||
|
||||
chan.wc = wc;
|
||||
chan.sendMsg = function (msg, cb) {
|
||||
cb = cb || function () {};
|
||||
var cmsg = chan.encryptor.encrypt(msg);
|
||||
wc.bcast(cmsg).then(function () {
|
||||
wc.bcast(msg).then(function () {
|
||||
if (/^cp\|/.test(msg)) {
|
||||
chan.history = [];
|
||||
} else {
|
||||
chan.history.push(msg);
|
||||
}
|
||||
cb();
|
||||
}, function (err) {
|
||||
cb({error: err});
|
||||
|
@ -118,7 +132,7 @@ define([
|
|||
if (parsed.validateKey && parsed.channel) { return; }
|
||||
// End of history: emit READY
|
||||
if (parsed.state && parsed.state === 1 && parsed.channel) {
|
||||
ctx.emit('READY', '');
|
||||
ctx.emit('READY', '', chan.clients);
|
||||
return;
|
||||
}
|
||||
if (parsed.error && parsed.channel) { return; }
|
||||
|
@ -126,20 +140,24 @@ define([
|
|||
var msg = parsed[4];
|
||||
|
||||
// Keep only the history for our channel
|
||||
if (msg[3] !== channel) { return; }
|
||||
if (parsed[3] !== channel) { return; }
|
||||
|
||||
if (chan.lastCp) {
|
||||
if (chan.lastCp === msg) {
|
||||
if (chan.lastCp === msg.slice(0, 11)) {
|
||||
delete chan.lastCp;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var isCp = /^cp\|/.test(msg);
|
||||
if (isCp) { return; }
|
||||
if (isCp) {
|
||||
chan.history = [];
|
||||
return;
|
||||
}
|
||||
|
||||
chan.lastKnownHash = msg.slice(0,64);
|
||||
ctx.emit('MESSAGE', msg, chan.clients);
|
||||
chan.history.push(msg);
|
||||
});
|
||||
|
||||
network.join(channel).then(onOpen, function (err) {
|
||||
|
@ -163,6 +181,9 @@ define([
|
|||
return void chan.sendMsg(data.isCp, cb);
|
||||
}
|
||||
chan.sendMsg(data.msg, cb);
|
||||
ctx.emit('MESSAGE', data.msg, chan.clients.filter(function (cl) {
|
||||
return cl !== clientId;
|
||||
}));
|
||||
};
|
||||
|
||||
var leaveChannel = function (ctx, padChan) {
|
||||
|
@ -224,7 +245,7 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
return cursor;
|
||||
return oo;
|
||||
};
|
||||
|
||||
return OO;
|
||||
|
|
Loading…
Reference in New Issue