Merge branch 'plugins' into 2024.6-test

This commit is contained in:
yflory 2024-06-21 18:49:26 +02:00
commit 179865304d
25 changed files with 519 additions and 41 deletions

View File

@ -16,6 +16,8 @@ www/accounts
www/worker
www/todo
#lib/plugins/
www/common/hyperscript.js
www/pad/wysiwygarea-plugin.js

View File

@ -22,11 +22,13 @@ define([
'/common/outer/login-block.js',
'/common/common-hash.js',
'/common/outer/http-command.js',
'/api/config',
'/components/tweetnacl/nacl-fast.min.js',
'/components/scrypt-async/scrypt-async.min.js', // better load speed
], function ($, Listmap, Crypto, Util, NetConfig, Login, Cred, ChainPad, Realtime, Constants, UI,
Feedback, h, LocalStore, Messages, nThen, Block, Hash, ServerCommand) {
Feedback, h, LocalStore, Messages, nThen, Block, Hash, ServerCommand,
ApiConfig) {
var Exports = {
Cred: Cred,
Block: Block,
@ -218,6 +220,11 @@ define([
proxy.edPublic = result.edPublic;
}
if (ApiConfig && Array.isArray(ApiConfig.adminKeys) &&
ApiConfig.adminKeys.includes(proxy.edPublic)) {
localStorage.CP_admin = "1";
}
setTimeout(function () {
Realtime.whenRealtimeSyncs(result.realtime, function () {
proceed(result);

View File

@ -45,6 +45,7 @@ var getLanguage = Messages._getLanguage = function () {
(map[l.split('_')[0]] ? l.split('_')[0] : 'en'));
};
var language = getLanguage();
window.cryptpadLanguage = language;
// Translations files were migrated from requirejs modules to json.
// To avoid asking every administrator to update their customized translation files,

View File

@ -15,7 +15,8 @@ define([
'/common/outer/local-store.js',
'/customize/pages.js',
'/common/pad-types.js',
], function ($, Config, h, Hash, Constants, Util, TextFit, Msg, AppConfig, LocalStore, Pages, PadTypes) {
'/common/extensions.js'
], function ($, Config, h, Hash, Constants, Util, TextFit, Msg, AppConfig, LocalStore, Pages, PadTypes, Extensions) {
var urlArgs = Config.requireConf.urlArgs;
var checkEarlyAccess = function (x) {
@ -164,9 +165,19 @@ define([
};
let popup = h('div.cp-extensions-popups');
let utils = { h, Util, Hash };
Extensions.getExtensions('HOMEPAGE_POPUP').forEach(ext => {
if (typeof(ext.check) === "function" && !ext.check()) { return; }
ext.getContent(utils, content => {
$(popup).append(h('div.cp-extensions-popup', content));
});
});
return [
h('div#cp-main', [
Pages.infopageTopbar(),
popup,
notice,
h('div.container.cp-container', [
h('div.row.cp-home-hero', [

View File

@ -297,6 +297,29 @@
}
}
.cp-extensions-popups {
width: 100%;
.cp-extensions-popup {
background-color: @cp_alertify-bg;
border-radius: @infopages-radius-L;
padding: 10px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2);
width: 400px;
max-width: 100%;
color: @cryptpad_text_col;
margin-left: 40px;
}
}
@media (max-width: 700px) {
.cp-extensions-popups {
max-width: 90%;
.cp-extensions-popup {
margin-left: 0;
}
}
}
@media (min-width: 576px) and (max-width: 767px) {
.container {
padding-left: 0;

View File

@ -78,15 +78,26 @@ COMMANDS.TOTP_REVOKE = TOTP.TOTP_REVOKE;
COMMANDS.TOTP_WRITE_BLOCK = TOTP.TOTP_WRITE_BLOCK; // Password change only for now (v5.5.0)
COMMANDS.TOTP_REMOVE_BLOCK = TOTP.TOTP_REMOVE_BLOCK;
try {
// SSO plugin may not be installed
const SSO = plugins.SSO && plugins.SSO.challenge;
COMMANDS.SSO_AUTH = SSO.SSO_AUTH;
COMMANDS.SSO_AUTH_CB = SSO.SSO_AUTH_CB;
COMMANDS.SSO_WRITE_BLOCK = SSO.SSO_WRITE_BLOCK; // Account creation only
COMMANDS.SSO_UPDATE_BLOCK = SSO.SSO_UPDATE_BLOCK; // Password change
COMMANDS.SSO_VALIDATE = SSO.SSO_VALIDATE;
} catch (e) {}
// Load challenges added by plugins
Object.keys(plugins || {}).forEach(id => {
try {
let plugin = plugins[id];
if (!plugin.challenge) { return; }
let commands = plugin.challenge;
Object.keys(commands).forEach(cmd => {
if (COMMANDS[cmd]) { return; } // Don't overwrite
COMMANDS[cmd] = commands[cmd];
});
} catch (e) {}
});
/*
const SSO = plugins.SSO && plugins.SSO.challenge;
COMMANDS.SSO_AUTH = SSO.SSO_AUTH;
COMMANDS.SSO_AUTH_CB = SSO.SSO_AUTH_CB;
COMMANDS.SSO_WRITE_BLOCK = SSO.SSO_WRITE_BLOCK; // Account creation only
COMMANDS.SSO_UPDATE_BLOCK = SSO.SSO_UPDATE_BLOCK; // Password change
COMMANDS.SSO_VALIDATE = SSO.SSO_VALIDATE;
*/
var randomToken = () => Nacl.util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-');

View File

@ -513,6 +513,11 @@ app.use("/block", (req, res, next) => {
next();
});
Object.keys(plugins || {}).forEach(name => {
let plugin = plugins[name];
if (!plugin.addHttpEndpoints) { return; }
plugin.addHttpEndpoints(Env, app);
});
app.use("/customize", Express.static('customize'));
app.use("/customize", Express.static('customize.dist'));
@ -626,6 +631,35 @@ var serveBroadcast = makeRouteCache(function () {
app.get('/api/config', serveConfig);
app.get('/api/broadcast', serveBroadcast);
(function () {
let extensions = plugins._extensions;
let styles = plugins._styles;
let str = JSON.stringify(extensions);
let str2 = JSON.stringify(styles);
let js = `let extensions = ${str};
let styles = ${str2};
let lang = window.cryptpadLanguage;
let paths = [];
extensions.forEach(name => {
paths.push(\`optional!/\${name}/extensions.js\`);
paths.push(\`optional!json!/\${name}/translations/messages.json\`);
paths.push(\`optional!json!/\${name}/translations/messages.\${lang}.json\`);
});
styles.forEach(name => {
paths.push(\`optional!less!/\${name}/style.less\`);
});
define(paths, function () {
let args = Array.prototype.slice.apply(arguments);
return args;
}, function () {
// ignore missing files
});`;
app.get('/extensions.js', (req, res) => {
res.setHeader('Content-Type', 'text/javascript');
res.send(js);
});
})();
var Define = function (obj) {
return `define(function (){
return ${JSON.stringify(obj, null, '\t')};
@ -719,7 +753,7 @@ app.post('/api/auth', function (req, res, next) {
});
app.use(function (req, res /*, next */) {
if (/^(\/favicon\.ico\/|.*\.js\.map)$/.test(req.url)) {
if (/^(\/favicon\.ico\/|.*\.js\.map|.*\/translations\/.*\.json)/.test(req.url)) {
// ignore common 404s
} else {
Log.info('HTTP_404', req.url);

View File

@ -4,6 +4,8 @@
const fs = require('node:fs');
const plugins = {};
const extensions = plugins._extensions = [];
const styles = plugins._styles = [];
try {
let pluginsDir = fs.readdirSync(__dirname + '/plugins');
@ -12,6 +14,18 @@ try {
try {
let plugin = require(`./plugins/${name}/index`);
plugins[plugin.name] = plugin.modules;
try {
let hasExt = fs.existsSync(`lib/plugins/${name}/client/extensions.js`);
if (hasExt) {
extensions.push(plugin.name.toLowerCase());
}
} catch (e) {}
try {
let hasStyle = fs.existsSync(`lib/plugins/${name}/client/style.less`);
if (hasStyle) {
styles.push(plugin.name.toLowerCase());
}
} catch (e) {}
} catch (err) {
console.error(err);
}

View File

@ -169,7 +169,23 @@ define([
}
};
const blocks = Sidebar.blocks('admin');
const blocks = sidebar.blocks;
// EXTENSION_POINT:ADMIN_CATEGORY
common.getExtensions('ADMIN_CATEGORY').forEach(ext => {
if (!ext || !ext.id || !ext.name || !ext.content) {
return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext);
}
if (categories[ext.id]) {
return console.error('Extension point ID already used', ext);
}
console.error(ext);
categories[ext.id] = {
icon: ext.icon,
name: ext.name,
content: ext.content
};
});
const flushCache = (cb) => {
cb = cb || function () {};
@ -3884,6 +3900,32 @@ define([
cb(opts);
});
// EXTENSION_POINT:ADMIN_ITEM
let utils = {
h, Util, Hash
};
common.getExtensions('ADMIN_ITEM').forEach(ext => {
if (!ext || !ext.id || typeof(ext.getContent) !== "function") {
return console.error('Invalid extension point', 'ADMIN_CATEGORY', ext);
}
if (sidebar.hasItem(ext.id)) {
return console.error('Extension point ID already used', ext);
}
sidebar.addItem(ext.id, cb => {
ext.getContent(common, blocks, utils, content => {
cb(content);
});
}, {
noTitle: !ext.title,
noHint: !ext.description,
title: ext.title,
hint: ext.description
});
});
sidebar.makeLeftside(categories);
};

View File

@ -2822,6 +2822,15 @@ define([
initFeedback(data.feedback);
}
if (data.edPublic) {
if (Array.isArray(Config.adminKeys) &&
Config.adminKeys.includes(data.edPublic)) {
// Doesn't provides extra-rights but may show
// additional warnings in the UI
localStorage.CP_admin = "1";
}
}
if (data.loggedIn) {
window.CP_logged_in = true;
}

58
www/common/extensions.js Normal file
View File

@ -0,0 +1,58 @@
define([
'optional!/extensions.js'
], (Extensions) => {
const ext = {};
if (!Array.isArray(Extensions) || !Extensions.length) { return ext; }
let all = Extensions.slice();
while(all.length) {
let current = all.splice(0, 3);
let f = current[0];
if (typeof(f) !== "function") {
continue;
}
let defaultLang = current[1];
let lang = current[2];
if (!Object.keys(lang).length && Object.keys(defaultLang).length) {
// If our language doesn't exists, use default
lang = defaultLang;
} else if (Object.keys(defaultLang).length) {
// Otherwise fill our language with missing keys
Object.keys(defaultLang).forEach(key => {
if (typeof(lang[key]) !== "undefined") { return; }
lang[key] = defaultLang[key];
});
}
lang._getKey = function (key, argArray) {
if (!lang[key]) { return '?'; }
var text = lang[key];
if (typeof(text) === 'string') {
return text.replace(/\{(\d+)\}/g, function (str, p1) {
if (typeof(argArray[p1]) === 'string' || typeof(argArray[p1]) === "number") {
return argArray[p1];
}
return '';
});
} else {
return text;
}
};
let currentExt = f(lang) || {};
Object.keys(currentExt).forEach(key => {
ext[key] = ext[key] || [];
Array.prototype.push.apply(ext[key], currentExt[key]); // concat in place
});
}
ext.getExtensions = id => {
let e = ext[id];
if (!Array.isArray(e)) { e = []; }
return e;
};
return ext;
});

View File

@ -262,9 +262,9 @@ define([
options = options || {};
const title = options.noTitle ? undefined : h('label.cp-item-label', {
id: `cp-${app}-${key}`
}, Messages[`${app}_${safeKey}Title`] || key);
}, options.title || Messages[`${app}_${safeKey}Title`] || key);
const hint = options.noHint ? undefined : h('span.cp-sidebarlayout-description',
Messages[`${app}_${safeKey}Hint`] || 'Coming soon...');
options.hint || Messages[`${app}_${safeKey}Hint`] || 'Coming soon...');
if (hint && options.htmlHint) {
hint.innerHTML = Messages[`${app}_${safeKey}Hint`];
}
@ -281,6 +281,10 @@ define([
});
};
sidebar.hasItem = key => {
return !key || !!items[key];
};
sidebar.addCheckboxItem = (data) => {
const key = data.key;
let blocks = sidebar.blocks;
@ -335,7 +339,7 @@ define([
'data-category': key
}, [
icon,
Messages[`${app}_cat_${key}`] || key,
category.name || Messages[`${app}_cat_${key}`] || key,
]);
var $item = $(item).appendTo(container);
Util.onClickEnter($item, function () {

View File

@ -107,9 +107,11 @@ define([
var myOOId;
var sessionId = Hash.createChannelId();
var cpNfInner;
let integrationChannel;
var evOnPatch = Util.mkEvent();
var evOnSync = Util.mkEvent();
var evIntegrationSave = Util.mkEvent();
// This structure is used for caching media data and blob urls for each media cryptpad url
var mediasData = {};
@ -313,7 +315,10 @@ define([
isCp: cp
}
}, function (err, h) {
if (!err) { evOnSync.fire(); }
if (!err) {
evOnSync.fire();
evIntegrationSave.fire();
}
cb(err, h);
});
},
@ -1423,6 +1428,9 @@ define([
debug(obj, 'toOO');
chan.event('CMD', obj);
if (obj && obj.type === "saveChanges") {
evIntegrationSave.fire();
}
};
chan.on('CMD', function (obj) {
@ -1844,6 +1852,11 @@ define([
}
delete APP.oldCursor;
}
if (integrationChannel) {
APP.onDocumentUnlock = () => {
integrationChannel.event('EV_INTEGRATION_READY');
};
}
}
delete APP.startNew;
@ -2580,6 +2593,22 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
});
};
sframeChan.on('EV_INTEGRATION_DOWNLOADAS', function (format) {
console.error('DOWNLOAD AS RECEIVED');
var data = getContent();
x2tConvertData(data, "document.bin", format, function (xlsData) {
UI.removeModals();
if (xlsData) {
var blob = new Blob([xlsData], {type: "application/bin;charset=utf-8"});
if (integrationChannel) {
integrationChannel.event('EV_INTEGRATION_ON_DOWNLOADAS',
blob, { raw: true });
}
return;
}
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).
@ -3132,6 +3161,73 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
UI.removeLoadingScreen();
};
let convertImportBlob = (blob, title) => {
new Response(blob).arrayBuffer().then(function (buffer) {
var u8Xlsx = new Uint8Array(buffer);
x2tImportData(u8Xlsx, title, 'bin', function (bin) {
if (!bin) {
return void UI.errorLoadingScreen(Messages.error);
}
var blob = new Blob([bin], {type: 'text/plain'});
var file = getFileType();
resetData(blob, file);
//saveToServer(blob, title);
Title.updateTitle(title);
UI.removeLoadingScreen();
});
});
};
if (privateData.integration) {
let cfg = privateData.integrationConfig || {};
common.openIntegrationChannel(APP.onLocal);
integrationChannel = common.getSframeChannel();
var integrationSave = function (cb) {
var ext = cfg.fileType;
var upload = Util.once(function (_blob) {
integrationChannel.query('Q_INTEGRATION_SAVE', {
blob: _blob
}, cb, {
raw: true
});
});
var data = getContent();
x2tConvertData(data, "document.bin", ext, function (xlsData) {
UI.removeModals();
if (xlsData) {
var blob = new Blob([xlsData], {type: "application/bin;charset=utf-8"});
upload(blob);
return;
}
UI.warn(Messages.error);
});
};
const integrationHasUnsavedChanges = function(unsavedChanges, cb) {
integrationChannel.query('Q_INTEGRATION_HAS_UNSAVED_CHANGES', unsavedChanges, cb);
};
var inte = common.createIntegration(integrationSave,
integrationHasUnsavedChanges);
if (inte) {
evIntegrationSave.reg(function () {
inte.changed();
});
}
integrationChannel.on('Q_INTEGRATION_NEEDSAVE', function (data, cb) {
integrationSave(function (obj) {
if (obj && obj.error) { console.error(obj.error); }
cb();
});
});
if (privateData.initialState) {
var blob = privateData.initialState;
let title = `document.${cfg.fileType}`;
console.error(blob, title);
return convertImportBlob(blob, title);
}
}
if (privateData.isNewFile && privateData.fromFileData) {
try {
(function () {

View File

@ -11,12 +11,15 @@ define([
'/common/sframe-common-outer.js'
], function (nThen, ApiConfig, DomReady, Hash, SFCommonO) {
var isIntegration = Boolean(window.CP_integration_outer);
var integration = window.CP_integration_outer || {};
// Loaded in load #2
var hash, href, version;
nThen(function (waitFor) {
DomReady.onReady(waitFor());
}).nThen(function (waitFor) {
var obj = SFCommonO.initIframe(waitFor, true);
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname);
href = obj.href;
hash = obj.hash;
var parsed = Hash.parsePadUrl(href);
@ -24,9 +27,14 @@ define([
var opts = parsed.getOptions();
version = opts.versionHash;
}
if (isIntegration) {
href = integration.href;
hash = integration.hash;
}
}).nThen(function (/*waitFor*/) {
var addData = function (obj) {
obj.ooType = window.location.pathname.replace(/^\//, '').replace(/\/$/, '');
let path = (integration && integration.pathname) || window.location.pathname;
obj.ooType = path.replace(/^\//, '').replace(/\/$/, '');
obj.ooVersionHash = version;
obj.ooForceVersion = localStorage.CryptPad_ooVersion || "";
};
@ -154,18 +162,21 @@ define([
Utils.initUnsafeIframe(obj, cb);
});
};
SFCommonO.start({
hash: hash,
href: href,
type: 'oo',
useCreationScreen: true,
addData: addData,
addRpc: addRpc,
getPropChannels: getPropChannels,
messaging: true
messaging: true,
useCreationScreen: !isIntegration,
noDrive: true,
integration: isIntegration,
integrationUtils: integration.utils,
integrationConfig: integration.config || {},
initialState: integration.initialState || undefined
});
});
});

View File

@ -3014,6 +3014,8 @@ define([
// Make sure we have a valid user object before emitting cacheready
if (rt.proxy && !rt.proxy.drive) { return; }
returned.edPublic = rt.proxy.edPublic;
onCacheReady(clientId, function () {
if (typeof(cb) === "function") { cb(returned); }
onCacheReadyEvt.fire();
@ -3047,6 +3049,8 @@ define([
drive[Constants.oldStorageKey] = [];
}
*/
returned.edPublic = rt.proxy.edPublic;
// Drive already exist: return the existing drive, don't load data from legacy store
if (store.manager) {
// If a cache is loading, make sure it is complete before calling onReady
@ -3156,6 +3160,7 @@ define([
loadUniversal(Cursor, 'cursor', function () {});
loadUniversal(Integration, 'integration', function () {});
loadUniversal(Messenger, 'messenger', function () {});
loadOnlyOffice();
store.messenger = store.modules['messenger'];
// And now we're ready

View File

@ -12,7 +12,7 @@ define([
var CURRENT_VERSION = X2T.CURRENT_VERSION = CurrentVersion.currentVersion;
var debug = function (str) {
if (localStorage.CryptPad_dev !== "1") { return; }
//if (localStorage.CryptPad_dev !== "1") { return; }
console.debug(str);
};

View File

@ -648,8 +648,8 @@ define([
const integrationHasUnsavedChanges = function(unsavedChanges, cb) {
integrationChannel.query('Q_INTEGRATION_HAS_UNSAVED_CHANGES', unsavedChanges, cb);
};
var inte = common.createIntegration(onLocal, cpNfInner.chainpad,
integrationSave, integrationHasUnsavedChanges);
var inte = common.createIntegration(integrationSave,
integrationHasUnsavedChanges);
if (inte) {
integration = true;
evIntegrationSave.reg(function () {

View File

@ -9,8 +9,6 @@ define([
module.create = function (
Common,
onLocal,
chainpad,
saveHandler,
unsavedChangesHandler) {

View File

@ -2077,6 +2077,16 @@ define([
cfg.integrationUtils.save(obj, cb);
}
});
sframeChan.on('EV_INTEGRATION_READY', function () {
if (cfg.integrationUtils && cfg.integrationUtils.onReady) {
cfg.integrationUtils.onReady();
}
});
sframeChan.on('EV_INTEGRATION_ON_DOWNLOADAS', function (obj) {
if (cfg.integrationUtils && cfg.integrationUtils.onDownloadAs) {
cfg.integrationUtils.onDownloadAs(obj);
}
});
sframeChan.on('Q_INTEGRATION_HAS_UNSAVED_CHANGES', function (obj, cb) {
if (cfg.integrationUtils && cfg.integrationUtils.onHasUnsavedChanges) {
cfg.integrationUtils.onHasUnsavedChanges(obj, cb);
@ -2090,6 +2100,15 @@ define([
integrationSave = function (cb) {
sframeChan.query('Q_INTEGRATION_NEEDSAVE', null, cb);
};
if (cfg.integrationUtils) {
if (cfg.integrationUtils.setDownloadAs) {
cfg.integrationUtils.setDownloadAs(format => {
sframeChan.event('EV_INTEGRATION_DOWNLOADAS', format);
});
}
}
}
if (cfg.messaging) {

View File

@ -34,6 +34,7 @@ define([
'/common/common-constants.js',
'/components/localforage/dist/localforage.min.js',
'/common/hyperscript.js',
'/common/extensions.js'
], function (
$,
ApiConfig,
@ -64,7 +65,8 @@ define([
Language,
Constants,
localForage,
h
h,
Ext
) {
// Chainpad Netflux Inner
var funcs = {};
@ -775,6 +777,8 @@ define([
return Util.checkRestrictedApp(app, AppConfig, ea, priv.plan, priv.loggedIn);
};
funcs.getExtensions = Ext.getExtensions;
funcs.mailbox = {};
Object.freeze(funcs);

View File

@ -14,6 +14,13 @@
var getTxid = function () {
return Math.random().toString(16).replace('0.', '');
};
var getInstanceURL = () => {
var scripts = document.getElementsByTagName('script');
for (var i = scripts.length - 1; i >= 0; i--) {
var match = scripts[i].src.match(/(.*)web-apps\/apps\/api\/documents\/api.js/i);
if (match) { return match[1]; }
}
};
var makeChan = function (iframe, iOrigin) {
var handlers = {};
@ -75,6 +82,7 @@
var makeIframe = function () {}; // placeholder
let onDocumentReady = [];
var start = function (config, chan) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
@ -83,7 +91,8 @@
var getBlob = function (cb) {
var xhr = new XMLHttpRequest();
xhr.open('GET', config.document.url, true);
let url = config.document.url;
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (this.status === 200) {
@ -131,9 +140,18 @@
var getSession = function (cb) {
chan.send('GET_SESSION', {
key: key
key: key,
keepOld: !config.events.onNewKey
}, function (obj) {
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
// OnlyOffice
if (!config.events.onNewKey) {
key = obj.key;
console.error(key, obj);
return void cb();
}
if (obj.key !== key) {
// The outside app may reject our new key if the "old" one is deprecated.
// This will happen if multiple users try to update the key at the same
@ -153,21 +171,52 @@
};
getSession(onKeyValidated);
chan.on('DOCUMENT_READY', function () {
if (config.events.onAppReady) {
config.events.onAppReady();
}
if (config.events.onReady) {
config.events.onReady();
}
if (config.events.onDocumentReady) {
config.events.onDocumentReady();
}
onDocumentReady.forEach(f => {
try { f(); } catch (e) { console.error(e); }
});
});
chan.on('ON_DOWNLOADAS', blob => {
let url = URL.createObjectURL(blob);
config.events.onDownloadAs({
data: {
fileType: config.document && config.document.fileType,
url
}
});
});
chan.on('SAVE', function (data, cb) {
blob = data;
config.events.onSave(data, cb);
});
chan.on('RELOAD', function () {
config.document.blob = blob;
document.getElementById('cryptpad-editor').remove();
if (!config.editorConfig) { // Not OnlyOffice shim
document.getElementById('cryptpad-editor').remove();
}
makeIframe(config);
});
chan.on('HAS_UNSAVED_CHANGES', function(unsavedChanges, cb) {
config.events.onHasUnsavedChanges(unsavedChanges);
if (config.events.onHasUnsavedChanges) {
config.events.onHasUnsavedChanges(unsavedChanges);
}
cb();
});
chan.on('ON_INSERT_IMAGE', function(data, cb) {
config.events.onInsertImage(data, cb);
if (config.events.onIntertImage) {
config.events.onInsertImage(data, cb);
} else { cb(); }
});
});
@ -192,7 +241,28 @@
* @return {promise}
*/
var init = function (cryptpadURL, containerId, config) {
return new Promise(function (resolve, reject) {
// OnlyOffice shim: don't provide a URL
if (!config && typeof(containerId) === "object") {
config = containerId;
containerId = cryptpadURL;
cryptpadURL = getInstanceURL();
}
// OnlyOffice shim
let url = config.document.url;
if (/^http:\/\/localhost\/cache\/files\//.test(url)) {
url = url.replace(/(http:\/\/localhost\/cache\/files\/)/, getInstanceURL() + 'ooapi/');
}
config.document.url = url;
if (config.documentType === "spreadsheet") {
config.documentType = "sheet";
}
if (config.documentType === "text") {
config.documentType = "doc";
}
let chan;
let ret = new Promise(function (resolve, reject) {
setTimeout(function () {
if (!cryptpadURL || typeof(cryptpadURL) !== "string") {
@ -209,8 +279,8 @@
if (!config) { return reject('Missing args: no data provided'); }
if(['document.url', 'document.fileType', 'documentType',
'events.onSave', 'events.onHasUnsavedChanges',
'events.onNewKey', 'events.onInsertImage'].some(function (k) {
/*'events.onSave', 'events.onHasUnsavedChanges',
'events.onNewKey', 'events.onInsertImage'*/].some(function (k) {
var s = k.split('.');
var c = config;
return s.some(function (key) {
@ -235,14 +305,23 @@
makeIframe = function (config) {
var iframe = document.createElement('iframe');
iframe.setAttribute('id', 'cryptpad-editor');
iframe.setAttribute('name', 'frameEditor');
iframe.setAttribute('align', 'top');
iframe.setAttribute("src", url);
container.appendChild(iframe);
iframe.setAttribute("width", config.width);
iframe.setAttribute("height", config.height);
if (config.editorConfig) { // OnlyOffice
container.replaceWith(iframe);
container = iframe;
} else {
container.appendChild(iframe);
}
var onMsg = function (msg) {
var data = typeof(msg.data) === "string" ? JSON.parse(msg.data) : msg.data;
if (!data || data.q !== 'INTEGRATION_READY') { return; }
window.removeEventListener('message', onMsg);
var chan = makeChan(iframe, parsed.origin);
chan = makeChan(iframe, parsed.origin);
start(config, chan).then(resolve).catch(reject);
};
window.addEventListener('message', onMsg);
@ -250,8 +329,24 @@
makeIframe(config);
});
});
ret.downloadAs = (arg) => {
if (!chan) {
return void onDocumentReady.push(() => {
ret.downloadAs(arg);
});
}
chan.send('DOWNLOAD_AS', arg);
};
return ret;
};
init.version = () => { return '7.3.0'; };
init.DocEditor = init; // OnlyOffice shim
window.DocsAPI = init;
return init;
};

View File

@ -174,6 +174,7 @@ define([
edPublic: proxy.edPublic
}, function (e) {
if (e) { UI.alert(Messages.error); return console.error(e); }
localStorage.CP_admin = "1";
startOnboarding(data.network, proxy);
});
});

View File

@ -96,6 +96,13 @@ define([
http.send();
};
chan.on('GET_SESSION', function (data, cb) {
if (data.keepOld) {
var key = data.key + "000000000000000000000000000000000";
console.warn('KEY', key);
return void cb({
key: `/2/integration/edit/${key.slice(0,24)}/`
});
}
var getHash = function () {
//isNew = true;
return Hash.createRandomHash('integration');
@ -126,6 +133,24 @@ define([
var onInsertImage = function (data, cb) {
chan.send('ON_INSERT_IMAGE', data, cb);
};
var onReady = function () {
chan.send('DOCUMENT_READY', {});
};
let downloadAs;
chan.on('DOWNLOAD_AS', function (format) {
if (typeof(downloadAs) !== "function") {
console.error('UNSUPPORTED COMMAND', 'downloadAs');
return;
}
downloadAs(format);
});
let setDownloadAs = f => {
downloadAs = f;
};
let onDownloadAs = function (blob) { // DownloadAs callback
chan.send('ON_DOWNLOADAS', blob);
};
chan.on('START', function (data) {
console.warn('INNER START', data);
@ -141,13 +166,20 @@ define([
autosave: data.autosave
},
utils: {
onReady: onReady,
onDownloadAs,
setDownloadAs,
save: save,
reload: reload,
onHasUnsavedChanges: onHasUnsavedChanges,
onInsertImage: onInsertImage
}
};
require(['/common/sframe-app-outer.js'], function () {
let path = "/common/sframe-app-outer.js";
if (['sheet', 'doc', 'presentation'].includes(data.application)) {
path = '/common/onlyoffice/main.js';
}
require([path], function () {
console.warn('SAO REQUIRED');
delete window.CP_integration_outer;
});

View File

@ -13,7 +13,7 @@ define("optional", [], {
var onLoadFailure = function(err){
// optional module failed to load.
var failedId = err.requireModules && err.requireModules[0];
console.warn("Could not load optional module: " + failedId);
//console.warn("Could not load optional module: " + failedId);
// Undefine the module to cleanup internal stuff in requireJS
requirejs.undef(failedId);

View File

@ -0,0 +1 @@
../../../../cryptpad-api.js