Compare commits

...

42 commits

Author SHA1 Message Date
Wolfgang Ginolas
9f69feb244 Use image handling of OO fork 2024-07-10 15:44:39 +02:00
Wolfgang Ginolas
0ccac55a49 Let onlyoffice-editor handle auth 2024-07-09 15:16:19 +02:00
Wolfgang Ginolas
6ee8ff5e57 Readd OnlyOffice v1 2024-07-05 16:43:09 +02:00
Wolfgang Ginolas
2f8cb0dac6 Merge remote-tracking branch 'origin/staging' into insert-onlyoffice-api 2024-07-05 16:37:30 +02:00
Wolfgang Ginolas
86851f4f30 Merge remote-tracking branch 'origin/staging' into insert-onlyoffice-api 2024-07-01 10:22:23 +02:00
Wolfgang Ginolas
5cfbecc119 Manual cherry-pick: API: support downloadAs command 2024-07-01 09:46:10 +02:00
Wolfgang Ginolas
e3613ed97e Manual cherry-pick: Support OO apps in the API 2024-07-01 09:41:43 +02:00
Wolfgang Ginolas
0573b76bb1 Fix install-onlyoffice.sh 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
9b2fc90476 Load OO from window again 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
0309a2462e Update to version 7 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
944eaf2a53 Rename onlyoffice-api to onlyoffice-editor 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
d855d0b884 Fix usage of legacy channel and some cleanups 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
798fff51ba Use installLegacyChannel 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
fbaf81090c Use OnlyOffice v7 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
4f1f7f6d6d Use channels for old OnlyOffice versions 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
716ce828ff Use one constant for the OnlyOffice version 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
d1f5a25cdd Replace OO channel with OOApi 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
d172b420e7 Communicate via OOApi 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
6df12cd813 Script is loaded by OOApi now 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
a90470c8d9 Pass (dummy) URL to OnlyOfficeEditor 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
bf89d0a601 Replace oo-api with external dependecy 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
6d6c026e0d A working version before moving oo-api to another repo 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
ecc3950387 WIP insert queue 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
b4a45f0351 WIP add some logging 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
7040ccd184 WIP2 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
ff1173ac9e WIP 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
d66420496e Split onlyoffice/inner in smaller functions 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
90d27e68a9 [wip] started with API proof of concept 2024-06-27 14:53:35 +02:00
yflory
792d27c896 Fix CodeMirror focus issue 2024-06-27 14:53:35 +02:00
yflory
5f269fcff8 lint compliance 2024-06-27 14:53:35 +02:00
mathilde-cryptpad
e6ab5a90ac explain with easier words the purpose of httpSafePort 2024-06-27 14:53:35 +02:00
daria
ef0c8cd39f change shortcut for getting out of text editors Code/Slides 2024-06-27 14:53:35 +02:00
daria
97ccc16925 add shortcut for getting out of Code editor 2024-06-27 14:53:35 +02:00
daria
ec59395bca add outline to focused elements on Code/Markdown tools 2024-06-27 14:53:35 +02:00
Fabrice Mouhartem
ceeebd679a Remove redraw in notification dropdown
- Created square angles on the right side of the notification dropdown
  when hovering above the dismiss () button
- Fix #1465
2024-06-27 14:53:35 +02:00
Fabrice Mouhartem
46f8c04b3c maintenance: another typo in the comments… 2024-06-27 14:53:35 +02:00
Fabrice Mouhartem
5a4d78a56c maintenance: fix typo in comments (minor) 2024-06-27 14:53:35 +02:00
Fabrice Mouhartem
83b52a221f #1089: Contextual menu open on anonymous drive
- Related to https://github.com/cryptpad/cryptpad/issues/1089#issuecomment-2044954222
2024-06-27 14:53:35 +02:00
mathilde-cryptpad
c971cf1527 clarify how to use the different ports, see #1212 2024-06-27 14:53:35 +02:00
mathilde-cryptpad
41fd888a39 update Nginx examples with the new http2 option 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
4d748bd908 Remove duplicate args_isString 2024-06-27 14:53:35 +02:00
Wolfgang Ginolas
d58497ae8e Tighten eslint rules 2024-06-27 14:53:35 +02:00
4 changed files with 571 additions and 582 deletions

View file

@ -33,7 +33,7 @@ main() {
install_version v4 6ebc6938
install_version v5 88a356f0
install_version v6 abd8a309
install_version v7 ba82142f
install_version v7 2792e6e1
install_x2t v7.3+1 ab0c05b0e4c81071acea83f0c6a8e75f5870c360ec4abc4af09105dd9b52264af9711ec0b7020e87095193ac9b6e20305e446f2321a541f743626a598e5318c1
rm -rf "$BUILDS_DIR"

27
package-lock.json generated
View file

@ -44,6 +44,7 @@
"netflux-websocket": "^1.2.0",
"notp": "^2.0.3",
"nthen": "0.1.8",
"onlyoffice-editor": "file:../onlyoffice-editor",
"open-sans-fontface": "^1.4.0",
"openid-client": "^5.4.2",
"pako": "^2.1.0",
@ -74,6 +75,28 @@
"url": "https://opencollective.com/cryptpad"
}
},
"../onlyoffice-api": {
"version": "0.0.1",
"extraneous": true,
"license": "AGPL-3.0-or-later",
"devDependencies": {
"parcel": "^2.12.0"
}
},
"../onlyoffice-editor": {
"version": "0.0.1",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@eslint/js": "^9.0.0",
"eslint": "^8.57.0",
"prettier": "3.2.5",
"ts-loader": "^9.5.1",
"typescript": "^5.4.5",
"typescript-eslint": "^7.7.0",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
@ -3654,6 +3677,10 @@
"wrappy": "1"
}
},
"node_modules/onlyoffice-editor": {
"resolved": "../onlyoffice-editor",
"link": true
},
"node_modules/open-sans-fontface": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/open-sans-fontface/-/open-sans-fontface-1.4.0.tgz",

View file

@ -2,6 +2,10 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
define({
currentVersion: 'v7'
define(() => {
const version = 7;
return {
currentVersionNumber: version,
currentVersion: 'v' + version
};
});

View file

@ -16,16 +16,14 @@ define([
'/common/hyperscript.js',
'/api/config',
'/customize/messages.js',
'/customize/application_config.js',
'/components/chainpad/chainpad.dist.js',
'/file/file-crypto.js',
'/common/onlyoffice/history.js',
'/common/onlyoffice/oocell_base.js',
'/common/onlyoffice/oodoc_base.js',
'/common/onlyoffice/ooslide_base.js',
'/common/outer/worker-channel.js',
'/common/outer/x2t.js',
'/common/onlyoffice/current-version.js',
'/components/file-saver/FileSaver.min.js',
'css!/components/bootstrap/dist/css/bootstrap.min.css',
@ -45,15 +43,13 @@ define([
h,
ApiConfig,
Messages,
AppConfig,
ChainPad,
FileCrypto,
History,
EmptyCell,
EmptyDoc,
EmptySlide,
Channel,
X2T)
OOCurrentVersion)
{
var saveAs = window.saveAs;
var Nacl = window.nacl;
@ -65,9 +61,7 @@ define([
var CHECKPOINT_INTERVAL = 100;
var FORCE_CHECKPOINT_INTERVAL = 10000;
var DISPLAY_RESTORE_BUTTON = false;
var NEW_VERSION = 7; // version of the .bin, patches and ChainPad formats
var PENDING_TIMEOUT = 30000;
var CURRENT_VERSION = X2T.CURRENT_VERSION;
//var READONLY_REFRESH_TO = 15000;
@ -98,7 +92,7 @@ define([
hashes: {},
ids: {},
mediasSources: {},
version: privateData.ooForceVersion ? Number(privateData.ooForceVersion) : NEW_VERSION
version: privateData.ooForceVersion ? Number(privateData.ooForceVersion) : OOCurrentVersion.currentVersionNumber
};
var oldHashes = {};
var oldIds = {};
@ -111,7 +105,7 @@ define([
var evOnPatch = Util.mkEvent();
var evOnSync = Util.mkEvent();
var evIntegrationSave = Util.mkEvent();
const evIntegrationSave = Util.mkEvent();
// This structure is used for caching media data and blob urls for each media cryptpad url
var mediasData = {};
@ -398,9 +392,9 @@ define([
_content.hashes[1] = {
file: data.url,
index: 0,
version: NEW_VERSION
version: OOCurrentVersion.currentVersionNumber
};
_content.version = NEW_VERSION;
_content.version = OOCurrentVersion.currentVersionNumber;
_content.channel = Hash.createChannelId();
_content.ids = {};
sframeChan.query('Q_SAVE_AS_TEMPLATE', {
@ -454,7 +448,7 @@ define([
file: data.url,
hash: ev.hash,
index: ev.index,
version: NEW_VERSION
version: OOCurrentVersion.currentVersionNumber
};
oldHashes = JSON.parse(JSON.stringify(content.hashes));
content.locks = {};
@ -462,7 +456,7 @@ define([
// If this is a migration, set the new version
if (APP.migrate) {
delete content.migration;
content.version = NEW_VERSION;
content.version = OOCurrentVersion.currentVersionNumber;
}
APP.onLocal();
APP.realtime.onSettle(function () {
@ -1068,10 +1062,8 @@ define([
}
};
var handleAuth = function (obj, send) {
//setEditable(false);
var changes = [];
const getInitialChanges = function() {
const changes = [];
if (content.version > 2) {
ooChannel.queue.forEach(function (data) {
Array.prototype.push.apply(changes, data.msg.changes);
@ -1081,55 +1073,14 @@ define([
ooChannel.cpIndex += ooChannel.queue.length;
var last = ooChannel.queue.pop();
if (last) { ooChannel.lastHash = last.hash; }
} else {
}
return changes;
};
const onAuth = function () {
if (content.version <= 2) {
setEditable(false, true);
}
send({
type: "authChanges",
changes: changes
});
// Answer to the auth command
var p = getParticipants();
send({
type: "auth",
result: 1,
sessionId: sessionId,
participants: p.list,
locks: [],
changes: [],
changesIndex: 0,
indexUser: p.index,
buildVersion: "5.2.6",
buildNumber: 2,
licenseType: 3,
//"g_cAscSpellCheckUrl": "/spellchecker",
//"settings":{"spellcheckerUrl":"/spellchecker","reconnection":{"attempts":50,"delay":2000}}
});
// Open the document
send({
type: "documentOpen",
data: {"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
});
/*
// TODO: make sure we don't have new popups that can break our integration
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === "childList") {
for (var i = 0; i < mutation.addedNodes.length; i++) {
if (mutation.addedNodes[i].classList.contains('asc-window') &&
mutation.addedNodes[i].classList.contains('alert')) {
$(mutation.addedNodes[i]).find('button').not('.custom').click();
}
}
}
});
});
observer.observe(window.frames[0].document.body, {
childList: true,
});
*/
};
var handleLock = function (obj, send) {
@ -1401,43 +1352,29 @@ define([
});
};
var makeChannel = function () {
var msgEv = Util.mkEvent();
var iframe = $('#cp-app-oo-editor > iframe')[0].contentWindow;
var type = common.getMetadataMgr().getPrivateData().ooType;
window.addEventListener('message', function (msg) {
if (msg.source !== iframe) { return; }
msgEv.fire(msg);
});
var postMsg = function (data) {
iframe.postMessage(data, ApiConfig.httpSafeOrigin);
};
Channel.create(msgEv, postMsg, function (chan) {
APP.chan = chan;
var send = ooChannel.send = function (obj, force) {
const send = ooChannel.send = function (obj, force) {
// can't push to OO before reloading cp
if (APP.onStrictSaveChanges && !force) { return; }
// We only need to release locks for sheets
const type = common.getMetadataMgr().getPrivateData().ooType;
if (type !== "sheet" && obj.type === "releaseLock") { return; }
if (type === "presentation" && obj.type === "cp_theme") {
console.error(obj);
return;
}
debug(obj, 'toOO');
chan.event('CMD', obj);
debug(obj, 'toOOClient');
APP.docEditor.sendMessageToOO(obj);
if (obj && obj.type === "saveChanges") {
evIntegrationSave.fire();
}
};
chan.on('CMD', function (obj) {
debug(obj, 'fromOO');
const fromOOHandler = function (obj) {
debug(obj, 'fromOOClient');
switch (obj.type) {
case "auth":
handleAuth(obj, send);
// Handled by onlyoffice-editor now
break;
case "isSaveLock":
// TODO ping the server to check if we're online first?
@ -1480,6 +1417,7 @@ define([
case "saveChanges":
// If we have unsaved data before reloading for a checkpoint...
if (APP.onStrictSaveChanges) {
const type = common.getMetadataMgr().getPrivateData().ooType;
delete APP.unsavedLocks;
APP.unsavedChanges = {
type: "saveChanges",
@ -1599,8 +1537,6 @@ define([
}
break;
}
});
});
};
var x2tConvertData = function (data, fileName, format, cb) {
@ -1658,56 +1594,8 @@ define([
// to be downloaded and decrypted before converting to xlsx
var downloadImages = {};
var firstOO = true;
startOO = function (blob, file, force) {
if (APP.ooconfig && !force) { return void console.error('already started'); }
var url = URL.createObjectURL(blob);
var lock = !APP.history && (APP.migrate);
var fromContent = metadataMgr.getPrivateData().fromContent;
if (!firstOO) { fromContent = undefined; }
firstOO = false;
// Starting from version 3, we can use the view mode again
// defined but never used
//var mode = (content && content.version > 2 && lock) ? "view" : "edit";
var lang = (window.cryptpadLanguage || navigator.language || navigator.userLanguage || '').slice(0,2);
// Config
APP.ooconfig = {
"document": {
"fileType": file.type,
"key": "fresh",
"title": file.title,
"url": url,
"permissions": {
"download": false,
"print": true,
}
},
"documentType": file.doc,
"editorConfig": {
customization: {
chat: false,
logo: {
url: "/bounce/#" + encodeURIComponent('https://www.onlyoffice.com')
},
comments: !lock && !readOnly
},
"user": {
"id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
"firstname": metadataMgr.getUserData().name || Messages.anonymous,
"name": metadataMgr.getUserData().name || Messages.anonymous,
},
"mode": "edit",
"lang": lang
},
"events": {
"onAppReady": function(/*evt*/) {
var $iframe = $('iframe[name="frameEditor"]').contents();
$iframe.prop('tabindex', '-1');
var $tb = $iframe.find('head');
const onAppReady = function() {
APP.docEditor.getIframe().setAttribute('tabindex', '-1');
var css = // Old OO
//'#id-toolbar-full .toolbar-group:nth-child(2), #id-toolbar-full .separator:nth-child(3) { display: none; }' +
//'#fm-btn-save { display: none !important; }' +
@ -1736,7 +1624,7 @@ define([
//css += '#app-title { display: none !important; }'; // OnlyOffice logo + doc title
//css += '#file-menu-panel { top: 28px !important; }'; // Position of the "File" menu
}
$('<style>').text(css).appendTo($tb);
APP.docEditor.injectCSS(css);
setTimeout(function () {
$(window).trigger('resize');
});
@ -1745,15 +1633,17 @@ define([
window.setTimeout(function () { UI.findOKButton().focus(); });
});
}
},
"onError": function () {
};
const onError = function() {
console.error(arguments);
if (APP.isDownload) {
var sframeChan = common.getSframeChannel();
sframeChan.event('EV_OOIFRAME_DONE', '');
}
},
"onDocumentReady": function () {
};
const onDocumentReady = function(lock, lang, fromContent, file, force) {
evOnSync.fire();
var onMigrateRdy = Util.mkEvent();
onMigrateRdy.reg(function () {
@ -1926,9 +1816,63 @@ define([
}];
common.checkTrimHistory(channels);
}
};
const createOOConfig = function(blob, file, lock, fromContent, lang, force) {
const url = URL.createObjectURL(blob);
return {
"document": {
"fileType": file.type,
"key": "fresh",
"title": file.title,
"url": url,
"permissions": {
"download": false,
"print": true,
}
},
"documentType": file.doc,
"editorConfig": {
customization: {
chat: false,
logo: {
url: "/bounce/#" + encodeURIComponent('https://www.onlyoffice.com')
},
comments: !lock && !readOnly
},
"user": {
"id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
"firstname": metadataMgr.getUserData().name || Messages.anonymous,
"name": metadataMgr.getUserData().name || Messages.anonymous,
},
"mode": "edit",
"lang": lang
},
"events": {
"onAppReady": onAppReady,
"onError": onError,
"onDocumentReady": () => onDocumentReady(lock, lang, fromContent, file, force),
}
};
};
var firstOO = true;
startOO = function (blob, file, force) {
if (APP.ooconfig && !force) { return void console.error('already started'); }
const lock = !APP.history && (APP.migrate);
let fromContent = metadataMgr.getPrivateData().fromContent;
if (!firstOO) { fromContent = undefined; }
firstOO = false;
// Starting from version 3, we can use the view mode again
// defined but never used
//var mode = (content && content.version > 2 && lock) ? "view" : "edit";
const lang = (window.cryptpadLanguage || navigator.language || navigator.userLanguage || '').slice(0,2);
// Config
APP.ooconfig = createOOConfig(blob, file, lock, fromContent, lang, force);
/*
// NOTE: Make sure it won't break anaything new (Firefox setTimeout bug)
window.onbeforeunload = function () {
@ -2004,7 +1948,7 @@ define([
APP.onLocal();
APP.realtime.onSettle(function () {
APP.getImageURL(name, function(url) {
getImageURL(name).then(function(url) {
debug("CRYPTPAD success add " + name);
common.setPadAttribute('atime', +new Date(), null, data.href);
APP.AddImageSuccessCallback({
@ -2039,9 +1983,10 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
};
APP.loadingImage = 0;
APP.getImageURL = function(name, callback) {
const getImageURL = function(name) {
return new Promise((resolve) => {
if (name && /^data:image/.test(name)) {
return void callback('');
return void resolve('');
}
var mediasSources = getMediasSources();
@ -2059,12 +2004,12 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
};
var b = new Blob([u8], {type: "image/jpeg"});
var blobUrl = URL.createObjectURL(b);
return void callback(blobUrl);
return void resolve(blobUrl);
});
return;
}
debug("CryptPad - could not find matching media for " + name);
return void callback("");
return void resolve("");
}
var blobUrl = (typeof mediasData[data.src] === 'undefined') ? "" : mediasData[data.src].blobUrl;
@ -2080,7 +2025,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
documentUrls.addImageUrl(data.name, blobUrl);
}
return void callback(blobUrl);
return void resolve(blobUrl);
}
APP.loadingImage++;
@ -2088,7 +2033,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
if (err) {
APP.loadingImage--;
console.error(err);
return void callback("");
return void resolve("");
}
try {
debug("Decrypt with key " + data.key);
@ -2096,7 +2041,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
APP.loadingImage--;
if (err || !res.content) {
debug("Decrypting failed");
return void callback("");
return void resolve("");
}
try {
@ -2117,21 +2062,33 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
reader.readAsArrayBuffer(res.content);
debug("Adding CryptPad Image " + data.name + ": " + blobUrl);
window.frames[0].AscCommon.g_oDocumentUrls.addImageUrl(data.name, blobUrl);
callback(blobUrl);
resolve(blobUrl);
} catch (e) {}
});
} catch (e) {
APP.loadingImage--;
debug("Exception decrypting image " + data.name);
console.error(e);
callback("");
resolve("");
}
}, void 0, common.getCache());
});
};
APP.docEditor = new window.DocsAPI.DocEditor("cp-app-oo-placeholder-a", APP.ooconfig);
ooLoaded = true;
makeChannel();
// TODO move this back to CryptPad
// if (content.version < 7) {
// APP.docEditor.installLegacyChannel();
// }
APP.docEditor.connectMockServer({
onMessage: fromOOHandler,
getParticipants: getParticipants,
onAuth: onAuth,
getImageURL: getImageURL,
getInitialChanges: getInitialChanges,
});
};
APP.printPdf = function (obj, cb) {
@ -2609,6 +2566,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
UI.warn(Messages.error);
});
});
sframeChan.on('EV_OOIFRAME_REFRESH', function (data) {
// We want to get the "bin" content of a sheet from its json in order to download
// something useful from a non-onlyoffice app (download from drive or settings).
@ -2624,7 +2582,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
content = json.content;
readOnly = true;
var version = (!content.version || content.version === 1) ? 'v1/' :
(content.version <= 3 ? 'v2b/' : CURRENT_VERSION+'/');
(content.version <= 3 ? 'v2b/' : OOCurrentVersion.currentVersion + '/');
var s = h('script', {
type:'text/javascript',
src: '/common/onlyoffice/dist/'+version+'web-apps/apps/api/documents/api.js'
@ -2983,7 +2941,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
APP.startNew = isNew;
var version = CURRENT_VERSION + '/';
var version = OOCurrentVersion.currentVersion + '/';
var msg;
// Old version detected: use the old OO and start the migration if we can
if (privateData.ooForceVersion) {