mirror of https://github.com/xwiki-labs/cryptpad
API: Add missing code for the OO compatibility
This commit is contained in:
parent
54307c3df9
commit
d3bb0374cf
|
@ -1,278 +0,0 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
var factory = function (/*Hash*/) {
|
||||
|
||||
// This API is used to load a CryptPad editor for a provided document in
|
||||
// an external platform.
|
||||
// The external platform needs to store a session key and make it
|
||||
// available to all users who needs to access the realtime editor.
|
||||
|
||||
var getTxid = function () {
|
||||
return Math.random().toString(16).replace('0.', '');
|
||||
};
|
||||
|
||||
var makeChan = function (iframe, iOrigin) {
|
||||
var handlers = {};
|
||||
var commands = {};
|
||||
|
||||
var iWindow = iframe.contentWindow;
|
||||
var _sendCb = function (txid, args) {
|
||||
iWindow.postMessage({ ack: txid, args: args}, iOrigin);
|
||||
};
|
||||
var onMsg = function (ev) {
|
||||
if (ev.source !== iWindow) { return; }
|
||||
var data = ev.data;
|
||||
|
||||
// On ack
|
||||
if (data.ack) {
|
||||
if (handlers[data.ack]) {
|
||||
handlers[data.ack](data.args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// On new command
|
||||
var msg = data.msg;
|
||||
var txid = data.txid;
|
||||
if (commands[msg.q]) {
|
||||
console.warn('OUTER RECEIVED QUERY', msg.q, msg.data);
|
||||
commands[msg.q](msg.data, function (args) {
|
||||
_sendCb(txid, args);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
window.addEventListener('message', onMsg);
|
||||
|
||||
var send = function (q, data, cb) {
|
||||
var txid = getTxid();
|
||||
if (cb) { handlers[txid] = cb; }
|
||||
|
||||
console.warn('OUTER SENT QUERY', q, data);
|
||||
iWindow.postMessage({ msg: {
|
||||
q: q,
|
||||
data: data,
|
||||
}, txid: txid}, iOrigin);
|
||||
setTimeout(function () {
|
||||
delete handlers[txid];
|
||||
}, 60000);
|
||||
};
|
||||
var on = function (q, handler) {
|
||||
if (typeof(handler) !== "function") { return; }
|
||||
commands[q] = handler;
|
||||
};
|
||||
|
||||
return {
|
||||
send: send,
|
||||
on: on
|
||||
};
|
||||
};
|
||||
|
||||
var makeIframe = function () {}; // placeholder
|
||||
|
||||
var start = function (config, chan) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
var key = config.document.key;
|
||||
var blob;
|
||||
|
||||
var getBlob = function (cb) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', config.document.url, true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onload = function () {
|
||||
if (this.status === 200) {
|
||||
var blob = this.response;
|
||||
// myBlob is now the blob that the object URL pointed to.
|
||||
cb(null, blob);
|
||||
} else {
|
||||
cb(this.status);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function (e) {
|
||||
cb(e.message);
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
var start = function () {
|
||||
config.document.key = key;
|
||||
chan.send('START', {
|
||||
key: key,
|
||||
application: config.documentType,
|
||||
document: blob,
|
||||
ext: config.document.fileType,
|
||||
autosave: config.autosave || 10
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||
resolve({});
|
||||
resolve = function () {};
|
||||
reject = function () {};
|
||||
});
|
||||
};
|
||||
|
||||
var onKeyValidated = function () {
|
||||
if (config.document.blob) { // This is a reload
|
||||
blob = config.document.blob;
|
||||
return start();
|
||||
}
|
||||
getBlob(function (err, _blob) {
|
||||
if (err) { reject(err); return console.error(err); }
|
||||
_blob.name = `document.${config.document.fileType}`;
|
||||
blob = _blob;
|
||||
start();
|
||||
});
|
||||
};
|
||||
|
||||
var getSession = function (cb) {
|
||||
if (!config.events.onNewKey) {
|
||||
return void cb();
|
||||
}
|
||||
chan.send('GET_SESSION', {
|
||||
key: key
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||
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
|
||||
// time and in this case, only the first user will be able to generate a key.
|
||||
return config.events.onNewKey({
|
||||
old: key,
|
||||
new: obj.key
|
||||
}, function (_key) {
|
||||
// Delay reloading tabs with deprecated key
|
||||
var to = _key !== obj.key ? 1000 : 0;
|
||||
key = _key || obj.key;
|
||||
setTimeout(cb, to);
|
||||
});
|
||||
}
|
||||
cb();
|
||||
});
|
||||
};
|
||||
getSession(onKeyValidated);
|
||||
|
||||
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();
|
||||
makeIframe(config);
|
||||
});
|
||||
chan.on('HAS_UNSAVED_CHANGES', function(unsavedChanges, cb) {
|
||||
config.events.onHasUnsavedChanges(unsavedChanges);
|
||||
cb();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var getInstanceURL = () => {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
for (var i = scripts.length - 1; i >= 0; i--) {
|
||||
match = scripts[i].src.match(/(.*)web-apps\/apps\/api\/documents\/api.js/i);
|
||||
if (match) { return match[1]; }
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Create a CryptPad collaborative editor for the provided document.
|
||||
*
|
||||
* @param {string} cryptpadURL The URL of the CryptPad server.
|
||||
* @param {string} containerID (optional) The ID of the HTML element containing the iframe.
|
||||
* @param {object} config The object containing configuration parameters.
|
||||
* @param {object} config.document The document to load.
|
||||
* @param {string} document.url The document URL.
|
||||
* @param {string} document.fileType The document extension (md, xml, html, etc.).
|
||||
* @param {string} document.key The collaborative session key.
|
||||
* @param {object} config.events Event handlers.
|
||||
* @param {function} events.onSave (blob, callback) The save function to store the document when edited.
|
||||
* @param {function} events.onNewKey (data, callback) The function called when a new key is used.
|
||||
* @param {string} config.documentType The editor to load in CryptPad.
|
||||
* @return {promise}
|
||||
*/
|
||||
var init = function (containerId, config) {
|
||||
var cryptpadURL = getInstanceURL();
|
||||
console.warn('URL', url);
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
|
||||
if (!cryptpadURL || typeof(cryptpadURL) !== "string") {
|
||||
return reject('Missing arg: cryptpadURL');
|
||||
}
|
||||
var container;
|
||||
if (containerId) {
|
||||
container = document.getElementById(containerId);
|
||||
}
|
||||
if (!container) {
|
||||
console.warn('No container provided, append to body');
|
||||
container = document.body;
|
||||
}
|
||||
|
||||
if (!config) { return reject('Missing args: no data provided'); }
|
||||
if(['document.url', 'document.fileType', 'documentType',
|
||||
'events.onSave', 'events.onHasUnsavedChanges',
|
||||
'events.onNewKey'].some(function (k) {
|
||||
var s = k.split('.');
|
||||
var c = config;
|
||||
return s.some(function (key) {
|
||||
if (!c[key]) {
|
||||
reject(`Missing args: no "config.${k}" provided`);
|
||||
return true;
|
||||
}
|
||||
c = c[key];
|
||||
});
|
||||
})) { return; }
|
||||
|
||||
cryptpadURL = cryptpadURL.replace(/(\/)+$/, '');
|
||||
var url = cryptpadURL + '/integration/';
|
||||
var parsed;
|
||||
try {
|
||||
parsed = new URL(url);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return reject('Invalid arg: cryptpadURL');
|
||||
}
|
||||
|
||||
makeIframe = function (config) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('id', 'cryptpad-editor');
|
||||
iframe.setAttribute("src", url);
|
||||
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);
|
||||
start(config, chan).then(resolve).catch(reject);
|
||||
};
|
||||
window.addEventListener('message', onMsg);
|
||||
};
|
||||
makeIframe(config);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
DocEditor: init
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory();
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([], function () {
|
||||
return factory();
|
||||
});
|
||||
} else {
|
||||
window.DocsAPI = window.CryptPadAPI = factory();
|
||||
}
|
||||
}());
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
web-apps/apps/api/documents/api.js
|
|
@ -0,0 +1,314 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
var factory = function (/*Hash*/) {
|
||||
|
||||
// This API is used to load a CryptPad editor for a provided document in
|
||||
// an external platform.
|
||||
// The external platform needs to store a session key and make it
|
||||
// available to all users who needs to access the realtime editor.
|
||||
|
||||
var getTxid = function () {
|
||||
return Math.random().toString(16).replace('0.', '');
|
||||
};
|
||||
|
||||
var makeChan = function (iframe, iOrigin) {
|
||||
var handlers = {};
|
||||
var commands = {};
|
||||
|
||||
var iWindow = iframe.contentWindow;
|
||||
var _sendCb = function (txid, args) {
|
||||
iWindow.postMessage({ ack: txid, args: args}, iOrigin);
|
||||
};
|
||||
var onMsg = function (ev) {
|
||||
if (ev.source !== iWindow) { return; }
|
||||
var data = ev.data;
|
||||
|
||||
// On ack
|
||||
if (data.ack) {
|
||||
if (handlers[data.ack]) {
|
||||
handlers[data.ack](data.args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// On new command
|
||||
var msg = data.msg;
|
||||
var txid = data.txid;
|
||||
if (commands[msg.q]) {
|
||||
console.warn('OUTER RECEIVED QUERY', msg.q, msg.data);
|
||||
commands[msg.q](msg.data, function (args) {
|
||||
_sendCb(txid, args);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
window.addEventListener('message', onMsg);
|
||||
|
||||
var send = function (q, data, cb) {
|
||||
var txid = getTxid();
|
||||
if (cb) { handlers[txid] = cb; }
|
||||
|
||||
console.warn('OUTER SENT QUERY', q, data);
|
||||
iWindow.postMessage({ msg: {
|
||||
q: q,
|
||||
data: data,
|
||||
}, txid: txid}, iOrigin);
|
||||
setTimeout(function () {
|
||||
delete handlers[txid];
|
||||
}, 60000);
|
||||
};
|
||||
var on = function (q, handler) {
|
||||
if (typeof(handler) !== "function") { return; }
|
||||
commands[q] = handler;
|
||||
};
|
||||
|
||||
return {
|
||||
send: send,
|
||||
on: on
|
||||
};
|
||||
};
|
||||
|
||||
function setCookie(all){
|
||||
const cookies = all.split(";");
|
||||
cookies.forEach((el) => {
|
||||
document.cookie = el;
|
||||
});
|
||||
}
|
||||
function deleteAllCookies() {
|
||||
const cookies = document.cookie.split(";");
|
||||
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
const cookie = cookies[i];
|
||||
const eqPos = cookie.indexOf("=");
|
||||
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
|
||||
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
}
|
||||
}
|
||||
|
||||
var makeIframe = function () {}; // placeholder
|
||||
|
||||
var start = function (config, chan) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
var key = config.document.key;
|
||||
console.error('config.document.key', key);
|
||||
var blob;
|
||||
|
||||
var getBlob = function (cb) {
|
||||
var c = document.cookie;
|
||||
deleteAllCookies();
|
||||
console.warn(document.cookie);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', config.document.url, true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onload = function () {
|
||||
setCookie(c);
|
||||
if (this.status === 200) {
|
||||
var blob = this.response;
|
||||
// myBlob is now the blob that the object URL pointed to.
|
||||
cb(null, blob);
|
||||
} else {
|
||||
cb(this.status);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function (e) {
|
||||
cb(e.message);
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
var start = function () {
|
||||
config.document.key = key;
|
||||
chan.send('START', {
|
||||
key: key,
|
||||
application: config.documentType,
|
||||
document: blob,
|
||||
ext: config.document.fileType,
|
||||
autosave: config.autosave || 10
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||
resolve({});
|
||||
resolve = function () {};
|
||||
reject = function () {};
|
||||
});
|
||||
};
|
||||
|
||||
var onKeyValidated = function () {
|
||||
if (config.document.blob) { // This is a reload
|
||||
blob = config.document.blob;
|
||||
return start();
|
||||
}
|
||||
getBlob(function (err, _blob) {
|
||||
if (err) { reject(err); return console.error(err); }
|
||||
_blob.name = `document.${config.document.fileType}`;
|
||||
blob = _blob;
|
||||
start();
|
||||
});
|
||||
};
|
||||
|
||||
var getSession = function (cb) {
|
||||
chan.send('GET_SESSION', {
|
||||
key: key,
|
||||
keepOld: !config.events.onNewKey
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
|
||||
|
||||
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
|
||||
// time and in this case, only the first user will be able to generate a key.
|
||||
return config.events.onNewKey({
|
||||
old: key,
|
||||
new: obj.key
|
||||
}, function (_key) {
|
||||
// Delay reloading tabs with deprecated key
|
||||
var to = _key !== obj.key ? 1000 : 0;
|
||||
key = _key || obj.key;
|
||||
setTimeout(cb, to);
|
||||
});
|
||||
}
|
||||
cb();
|
||||
});
|
||||
};
|
||||
getSession(onKeyValidated);
|
||||
|
||||
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();
|
||||
makeIframe(config);
|
||||
});
|
||||
chan.on('HAS_UNSAVED_CHANGES', function(unsavedChanges, cb) {
|
||||
config.events.onHasUnsavedChanges(unsavedChanges);
|
||||
cb();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
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]; }
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Create a CryptPad collaborative editor for the provided document.
|
||||
*
|
||||
* @param {string} cryptpadURL The URL of the CryptPad server.
|
||||
* @param {string} containerID (optional) The ID of the HTML element containing the iframe.
|
||||
* @param {object} config The object containing configuration parameters.
|
||||
* @param {object} config.document The document to load.
|
||||
* @param {string} document.url The document URL.
|
||||
* @param {string} document.fileType The document extension (md, xml, html, etc.).
|
||||
* @param {string} document.key The collaborative session key.
|
||||
* @param {object} config.events Event handlers.
|
||||
* @param {function} events.onSave (blob, callback) The save function to store the document when edited.
|
||||
* @param {function} events.onNewKey (data, callback) The function called when a new key is used.
|
||||
* @param {string} config.documentType The editor to load in CryptPad.
|
||||
* @return {promise}
|
||||
*/
|
||||
var init = function (containerId, config) {
|
||||
var cryptpadURL = getInstanceURL();
|
||||
console.warn('URL', cryptpadURL);
|
||||
console.error(config);
|
||||
// config.documentType = "code";
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
|
||||
if (!cryptpadURL || typeof(cryptpadURL) !== "string") {
|
||||
return reject('Missing arg: cryptpadURL');
|
||||
}
|
||||
var container;
|
||||
if (containerId) {
|
||||
container = document.getElementById(containerId);
|
||||
}
|
||||
if (!container) {
|
||||
console.warn('No container provided, append to body');
|
||||
container = document.body;
|
||||
}
|
||||
|
||||
if (!config) { return reject('Missing args: no data provided'); }
|
||||
if(['document.url', 'document.fileType', 'documentType',
|
||||
/*'events.onSave', 'events.onHasUnsavedChanges',
|
||||
'events.onNewKey'*/].some(function (k) {
|
||||
var s = k.split('.');
|
||||
var c = config;
|
||||
return s.some(function (key) {
|
||||
if (!c[key]) {
|
||||
reject(`Missing args: no "config.${k}" provided`);
|
||||
return true;
|
||||
}
|
||||
c = c[key];
|
||||
});
|
||||
})) { return; }
|
||||
|
||||
cryptpadURL = cryptpadURL.replace(/(\/)+$/, '');
|
||||
var url = cryptpadURL + '/integration/';
|
||||
var parsed;
|
||||
try {
|
||||
parsed = new URL(url);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return reject('Invalid arg: cryptpadURL');
|
||||
}
|
||||
|
||||
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);
|
||||
iframe.setAttribute("width", config.width);
|
||||
iframe.setAttribute("height", config.height);
|
||||
container.replaceWith(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);
|
||||
start(config, chan).then(resolve).catch(reject);
|
||||
};
|
||||
window.addEventListener('message', onMsg);
|
||||
};
|
||||
makeIframe(config);
|
||||
});
|
||||
});
|
||||
};
|
||||
init.version = () => { return '7.3.0'; };
|
||||
|
||||
return {
|
||||
DocEditor: init
|
||||
};
|
||||
};
|
||||
|
||||
console.log('CP API LOADED');
|
||||
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory();
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([], function () {
|
||||
window.DocsAPI = window.CryptPadAPI = factory();
|
||||
return window.DocsAPI;
|
||||
});
|
||||
} else {
|
||||
window.DocsAPI = window.CryptPadAPI = factory();
|
||||
}
|
||||
}());
|
||||
|
||||
|
Loading…
Reference in New Issue