Import OnlyOffice code from the 'onlyoffice' branch and sframe it
@ -0,0 +1,117 @@
|
||||
|
||||
const sockjs = require('sockjs');
|
||||
const co = require('co');
|
||||
try {
|
||||
config = require('./config');
|
||||
} catch (e) {
|
||||
console.log("You can customize the configuration by copying config.example.js to config.js");
|
||||
config = require('./config.example');
|
||||
}
|
||||
var origin = config.httpUnsafeOrigin || 'http://localhost:3000/';
|
||||
|
||||
exports.install = function(server, callbackFunction) {
|
||||
var sockjs_opts = {sockjs_url: ""},
|
||||
sockjs_echo = sockjs.createServer(sockjs_opts),
|
||||
urlParse = new RegExp("^/onlyoffice/doc/([0-9-.a-zA-Z_=]*)/c.+", 'i');
|
||||
|
||||
console.log("Start ooserver");
|
||||
console.log("Port " + sockjs_echo.port);
|
||||
|
||||
function getBaseUrl(protocol, hostHeader, forwardedProtoHeader, forwardedHostHeader) {
|
||||
var url = '';
|
||||
if (forwardedProtoHeader) {
|
||||
url += forwardedProtoHeader;
|
||||
} else if (protocol) {
|
||||
url += protocol;
|
||||
} else {
|
||||
url += 'http';
|
||||
}
|
||||
url += '://';
|
||||
if (forwardedHostHeader) {
|
||||
url += forwardedHostHeader;
|
||||
} else if (hostHeader) {
|
||||
url += hostHeader;
|
||||
} else {
|
||||
url += origin.slice(0, -1);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
function getBaseUrlByConnection(conn) {
|
||||
return getBaseUrl('', conn.headers['host'], conn.headers['x-forwarded-proto'], conn.headers['x-forwarded-host']);
|
||||
}
|
||||
|
||||
function sendData(conn, data) {
|
||||
conn.write(JSON.stringify(data));
|
||||
}
|
||||
function sendDataWarning(conn, msg) {
|
||||
sendData(conn, {type: "warning", message: msg});
|
||||
}
|
||||
function sendDataMessage(conn, msg) {
|
||||
sendData(conn, {type: "message", messages: msg});
|
||||
}
|
||||
|
||||
sockjs_echo.on('connection', function(conn) {
|
||||
console.log("ooserver in connection");
|
||||
if (null == conn) {
|
||||
console.log("null == conn");
|
||||
return;
|
||||
}
|
||||
conn.baseUrl = getBaseUrlByConnection(conn);
|
||||
console.log("BaseUrl: " + conn.baseUrl);
|
||||
conn.sessionIsSendWarning = false;
|
||||
conn.sessionTimeConnect = conn.sessionTimeLastAction = new Date().getTime();
|
||||
console.log("ooserver setting handlers");
|
||||
conn.on('data', function(message) {
|
||||
console.log("In data");
|
||||
return co(function* () {
|
||||
try {
|
||||
console.log("Received: " + message);
|
||||
var data = JSON.parse(message);
|
||||
switch (data.type) {
|
||||
case 'auth':
|
||||
console.log("Response auth");
|
||||
var fileUrl = origin + "onlyoffice/document/test.bin";
|
||||
if (data.openCmd.format=="xlsx")
|
||||
fileUrl = origin + "onlyoffice/spreadsheet/test.bin"
|
||||
else if (data.openCmd.format=="pptx")
|
||||
fileUrl = origin + "onlyoffice/presentation/test.bin"
|
||||
sendData(conn, {"type":"auth","result":1,"sessionId":"08e77705-dc5c-477d-b73a-b1a7cbca1e9b","sessionTimeConnect":1494226099270,"participants":[]});
|
||||
sendData(conn, {"type":"documentOpen","data":{"type":"open","status":"ok","data":{"Editor.bin":fileUrl}}});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error receiving response: docId = %s type = %s\r\n%s", docId, (data && data.type) ? data.type : 'null', e.stack);
|
||||
}
|
||||
});
|
||||
});
|
||||
conn.on('error', function() {
|
||||
console.log("On error");
|
||||
});
|
||||
conn.on('close', function() {
|
||||
return co(function* () {
|
||||
console.log("On close");
|
||||
});
|
||||
});
|
||||
console.log("ooserver sending welcome message");
|
||||
sendData(conn, {
|
||||
type: 'license',
|
||||
license: {
|
||||
type: 3,
|
||||
light: false,
|
||||
trial: false,
|
||||
rights: 1,
|
||||
buildVersion: "4.3.3",
|
||||
buildNumber: 4,
|
||||
branding: false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
sockjs_echo.installHandlers(server, {prefix: '/onlyoffice/doc/[0-9-.a-zA-Z_=]*/c', log: function(severity, message) {
|
||||
console.log(message);
|
||||
}});
|
||||
|
||||
callbackFunction();
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
git clone https://github.com/ldubost/web-apps.git
|
||||
git clone https://github.com/ldubost/sdkjs.git
|
||||
cd sdkjs
|
||||
make
|
||||
cd ..
|
||||
rm -rf ../web-apps
|
||||
cp -r web-apps/deploy/web-apps ..
|
||||
rm -rf ../sdkjs
|
||||
cp -r web-apps/deploy/sdkjs ..
|
||||
|
@ -0,0 +1,5 @@
|
||||
cd web-apps
|
||||
git pull
|
||||
cd ../sdkjs
|
||||
git pull
|
||||
make clean
|
@ -0,0 +1,38 @@
|
||||
@import (once) "../../customize/src/less2/include/browser.less";
|
||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
||||
@import (once) '../../customize/src/less2/include/avatar.less';
|
||||
|
||||
.toolbar_main();
|
||||
.fileupload_main();
|
||||
.alertify_main();
|
||||
|
||||
// body
|
||||
&.cp-app-oo {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
#cp-toolbar {
|
||||
display: flex; // We need this to remove a 3px border at the bottom of the toolbar
|
||||
}
|
||||
|
||||
.cp-cryptpad-toolbar {
|
||||
padding: 0px;
|
||||
display: inline-block;
|
||||
}
|
||||
#cp-app-oo-container {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
background-color: lightgrey;
|
||||
display: flex;
|
||||
}
|
||||
#ooframe {
|
||||
flex: 1;
|
||||
border:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
config = {
|
||||
"document": {
|
||||
"fileType": "docx",
|
||||
"key": "Khirz6zTPdfd7",
|
||||
"title": "test.docx",
|
||||
"url": "/onlyoffice/test.docx"
|
||||
},
|
||||
"documentType": "text",
|
||||
"editorConfig": {
|
||||
"user": {
|
||||
"id": "c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
||||
"name": "John Smith"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"onDocumentStateChange": function(evt) { console.log("in change"); window.top.APP.onLocal(); },
|
||||
"onReady": function(evt) { console.log("in onReady"); window.top.onOOReady(); }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var docEditor = new DocsAPI.DocEditor("placeholder", config);
|
||||
|
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="placeholder"></div>
|
||||
<script type="text/javascript" src="/onlyoffice/web-apps/apps/api/documents/api.js"></script>
|
||||
<script type="text/javascript" src="/onlyoffice/document/doc.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CryptPad</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
#sbox-iframe {
|
||||
position:fixed;
|
||||
top:0px;
|
||||
left:0px;
|
||||
bottom:0px;
|
||||
right:0px;
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
overflow:hidden;
|
||||
}
|
||||
#sbox-filePicker-iframe {
|
||||
position: fixed;
|
||||
top:0; left:0;
|
||||
bottom:0; right:0;
|
||||
width:100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="sbox-iframe">
|
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp-app-noscroll">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<script async data-bootload="/onlyoffice/document/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<style>
|
||||
.loading-hidden { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="cp-app-oo">
|
||||
<div id="cp-toolbar" class="cp-toolbar-container"></div>
|
||||
<div id="cp-app-oo-container">
|
||||
<iframe id="ooframe" src="document.html" width="100%" height="100%">
|
||||
</iframe>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -0,0 +1,308 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/common/toolbar3.js',
|
||||
'json.sortify',
|
||||
'/bower_components/nthen/index.js',
|
||||
'/common/sframe-common.js',
|
||||
'/common/common-interface.js',
|
||||
'/api/config',
|
||||
'/customize/messages.js',
|
||||
'/customize/application_config.js',
|
||||
'/bower_components/chainpad/chainpad.dist.js',
|
||||
|
||||
'/bower_components/file-saver/FileSaver.min.js',
|
||||
|
||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/customize/src/less2/main.less',
|
||||
], function (
|
||||
$,
|
||||
Toolbar,
|
||||
JSONSortify,
|
||||
nThen,
|
||||
SFCommon,
|
||||
UI,
|
||||
ApiConfig,
|
||||
Messages,
|
||||
AppConfig,
|
||||
ChainPad)
|
||||
{
|
||||
var saveAs = window.saveAs;
|
||||
|
||||
var ooReady = window.frames[0] && window.frames[0].frames[0] && window.frames[0].frames[0].editor;
|
||||
window.onOOReady = function () {
|
||||
ooReady = true;
|
||||
};
|
||||
|
||||
var APP = window.APP = {
|
||||
$: $
|
||||
};
|
||||
|
||||
var stringify = function (obj) {
|
||||
return JSONSortify(obj);
|
||||
};
|
||||
|
||||
var toolbar;
|
||||
|
||||
var andThen = function (common) {
|
||||
var config = {};
|
||||
|
||||
var emitResize = APP.emitResize = function () {
|
||||
var cw = $('#ooframe')[0].contentWindow;
|
||||
|
||||
var evt = cw.document.createEvent('UIEvents');
|
||||
evt.initUIEvent('resize', true, false, cw, 0);
|
||||
cw.dispatchEvent(evt);
|
||||
};
|
||||
|
||||
var saveToServer = APP.saveToServer = function () {
|
||||
config.onLocal();
|
||||
}
|
||||
|
||||
var callRemote = APP.callRemote = function() {
|
||||
config.onRemote();
|
||||
}
|
||||
|
||||
var saveDocument = APP.saveDocument = function () {
|
||||
var defaultName = "text.oot";
|
||||
UI.prompt(Messages.exportPrompt, defaultName, function (filename) {
|
||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||
console.log("In saveDocument");
|
||||
var content = window.frames[0].frames[0].editor.asc_nativeGetFile();
|
||||
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, filename);
|
||||
});
|
||||
};
|
||||
|
||||
var loadDocument = APP.loadDocument = function (content, file) {
|
||||
console.log("Read " + content);
|
||||
return;
|
||||
window.frames[0].frames[0].editor.asc_CloseFile();
|
||||
var openResult = {bSerFormat: true, data: content, url: "http://localhost:3000/onlyoffice/", changes: null};
|
||||
window.frames[0].frames[0].editor.openDocument(openResult);
|
||||
};
|
||||
|
||||
var readOnly = false;
|
||||
var initializing = true;
|
||||
var $bar = $('#cp-toolbar');
|
||||
var Title;
|
||||
var cpNfInner;
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
|
||||
config = {
|
||||
readOnly: readOnly,
|
||||
patchTransformer: ChainPad.NaiveJSONTransformer,
|
||||
// cryptpad debug logging (default is 1)
|
||||
// logLevel: 0,
|
||||
validateContent: function (content) {
|
||||
try {
|
||||
JSON.parse(content);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.log("Failed to parse, rejecting patch");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var setEditable = function (state) {
|
||||
console.log(state);
|
||||
};
|
||||
|
||||
var stringifyInner = function (textValue) {
|
||||
var obj = {
|
||||
content: textValue,
|
||||
metadata: metadataMgr.getMetadataLazy()
|
||||
};
|
||||
// stringify the json and send it into chainpad
|
||||
return stringify(obj);
|
||||
};
|
||||
|
||||
APP.onLocal = config.onLocal = function () {
|
||||
console.log(initializing, readOnly);
|
||||
if (initializing) { return; }
|
||||
if (readOnly) { return; }
|
||||
|
||||
if (!window.frames[0].frames[0] || !window.frames[0].frames[0].editor) {
|
||||
console.log("Cannot access editor");
|
||||
return;
|
||||
}
|
||||
console.log('ok');
|
||||
var data = window.frames[0].frames[0].editor.asc_nativeGetFile();
|
||||
var content = stringifyInner(data);
|
||||
APP.realtime.contentUpdate(content);
|
||||
};
|
||||
|
||||
config.onInit = function (info) {
|
||||
readOnly = metadataMgr.getPrivateData().readOnly;
|
||||
|
||||
Title = common.createTitle({});
|
||||
|
||||
var configTb = {
|
||||
displayed: [
|
||||
'userlist',
|
||||
'title',
|
||||
'useradmin',
|
||||
'spinner',
|
||||
'newpad',
|
||||
'share',
|
||||
'limit',
|
||||
'unpinnedWarning'
|
||||
],
|
||||
title: Title.getTitleConfig(),
|
||||
metadataMgr: metadataMgr,
|
||||
readOnly: readOnly,
|
||||
realtime: info.realtime,
|
||||
sfCommon: common,
|
||||
$container: $bar,
|
||||
$contentContainer: $('#cp-app-oo-container')
|
||||
};
|
||||
toolbar = APP.toolbar = Toolbar.create(configTb);
|
||||
Title.setToolbar(toolbar);
|
||||
|
||||
var $rightside = toolbar.$rightside;
|
||||
|
||||
|
||||
/* add an export button */
|
||||
var $export = common.createButton('export', true, {}, saveDocument);
|
||||
$rightside.append($export);
|
||||
var $import = common.createButton('import', true, {}, loadDocument);
|
||||
$rightside.append($import);
|
||||
var $save = common.createButton('save', true, {}, saveToServer);
|
||||
$save.click(function () {
|
||||
saveToServer();
|
||||
});
|
||||
$rightside.append($save);
|
||||
var $remote = common.createButton('remote', true, {}, callRemote);
|
||||
$remote.click(function () {
|
||||
callRemote();
|
||||
});
|
||||
$rightside.append($remote);
|
||||
|
||||
if (common.isLoggedIn()) {
|
||||
common.createButton('hashtag', true).appendTo($rightside);
|
||||
}
|
||||
|
||||
var $forget = common.createButton('forget', true, {}, function (err) {
|
||||
if (err) { return; }
|
||||
setEditable(false);
|
||||
});
|
||||
$rightside.append($forget);
|
||||
};
|
||||
|
||||
config.onReady = function (info) {
|
||||
if (APP.realtime !== info.realtime) {
|
||||
APP.realtime = info.realtime;
|
||||
}
|
||||
|
||||
if (!window.frames[0].frames[0] || !window.frames[0].frames[0].editor) {
|
||||
console.log("Cannot access editor");
|
||||
return;
|
||||
}
|
||||
|
||||
var userDoc = APP.realtime.getUserDoc();
|
||||
var isNew = false;
|
||||
var newDoc = '';
|
||||
if (userDoc === "" || userDoc === "{}") { isNew = true; }
|
||||
|
||||
if (userDoc !== "") {
|
||||
var hjson = JSON.parse(userDoc);
|
||||
|
||||
if (hjson && hjson.metadata) {
|
||||
metadataMgr.updateMetadata(hjson.metadata);
|
||||
}
|
||||
if (typeof (hjson) !== 'object' || Array.isArray(hjson) ||
|
||||
(hjson.metadata && typeof(hjson.metadata.type) !== 'undefined' &&
|
||||
hjson.metadata.type !== 'oo')) {
|
||||
var errorText = Messages.typeError;
|
||||
UI.errorLoadingScreen(errorText);
|
||||
throw new Error(errorText);
|
||||
}
|
||||
newDoc = hjson.content;
|
||||
} else {
|
||||
Title.updateTitle(Title.defaultTitle);
|
||||
}
|
||||
|
||||
loadDocument(newDoc);
|
||||
initializing = false;
|
||||
setEditable(!readOnly);
|
||||
UI.removeLoadingScreen();
|
||||
};
|
||||
|
||||
config.onRemote = function () {
|
||||
if (initializing) { return; }
|
||||
if (!window.frames[0].frames[0] || !window.frames[0].frames[0].editor) {
|
||||
console.log("Cannot access editor");
|
||||
return;
|
||||
}
|
||||
|
||||
// force readonly to prevent interlacing
|
||||
readOnly = true;
|
||||
|
||||
var previousData = window.frames[0].frames[0].editor.asc_nativeGetFile();
|
||||
var userDoc = APP.realtime.getUserDoc();
|
||||
|
||||
var json = JSON.parse(userDoc);
|
||||
if (json.metadata) {
|
||||
metadataMgr.updateMetadata(json.metadata);
|
||||
}
|
||||
var remoteDoc = json.content;
|
||||
if (remoteDoc!=previousData) {
|
||||
console.log("Remote content is different")
|
||||
console.log("Remote content hjson: " + remoteDoc);
|
||||
loadDocument(remoteDoc);
|
||||
common.notify();
|
||||
} else {
|
||||
console.log("Data is unchanged");
|
||||
}
|
||||
|
||||
readOnly = false;
|
||||
};
|
||||
|
||||
config.onAbort = function () {
|
||||
// inform of network disconnect
|
||||
setEditable(false);
|
||||
toolbar.failed();
|
||||
UI.alert(Messages.common_connectionLost, undefined, true);
|
||||
};
|
||||
|
||||
config.onConnectionChange = function (info) {
|
||||
setEditable(info.state);
|
||||
if (info.state) {
|
||||
initializing = true;
|
||||
UI.findOKButton().click();
|
||||
} else {
|
||||
UI.alert(Messages.common_connectionLost, undefined, true);
|
||||
}
|
||||
};
|
||||
|
||||
cpNfInner = common.startRealtime(config);
|
||||
|
||||
cpNfInner.onInfiniteSpinner(function () {
|
||||
setEditable(false);
|
||||
UI.confirm(Messages.realtime_unrecoverableError, function (yes) {
|
||||
if (!yes) { return; }
|
||||
common.gotoURL();
|
||||
});
|
||||
});
|
||||
|
||||
common.onLogout(function () { setEditable(false); });
|
||||
};
|
||||
|
||||
var main = function () {
|
||||
var common;
|
||||
|
||||
nThen(function (waitFor) {
|
||||
if (!ooReady) {
|
||||
window.onOOReady = waitFor();
|
||||
}
|
||||
$(waitFor(function () {
|
||||
UI.addLoadingScreen();
|
||||
}));
|
||||
SFCommon.create(waitFor(function (c) { APP.common = common = c; }));
|
||||
}).nThen(function (/*waitFor*/) {
|
||||
andThen(common);
|
||||
});
|
||||
};
|
||||
main();
|
||||
});
|
@ -0,0 +1,43 @@
|
||||
// Load #1, load as little as possible because we are in a race to get the loading screen up.
|
||||
define([
|
||||
'/bower_components/nthen/index.js',
|
||||
'/api/config',
|
||||
'/common/dom-ready.js',
|
||||
'/common/requireconfig.js',
|
||||
'/common/sframe-common-outer.js'
|
||||
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||
var requireConfig = RequireConfig();
|
||||
|
||||
// Loaded in load #2
|
||||
nThen(function (waitFor) {
|
||||
DomReady.onReady(waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
var req = {
|
||||
cfg: requireConfig,
|
||||
req: [ '/common/loading.js' ],
|
||||
pfx: window.location.origin
|
||||
};
|
||||
window.rc = requireConfig;
|
||||
window.apiconf = ApiConfig;
|
||||
document.getElementById('sbox-iframe').setAttribute('src',
|
||||
ApiConfig.httpSafeOrigin + '/onlyoffice/document/inner.html?' + requireConfig.urlArgs +
|
||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||
|
||||
// This is a cheap trick to avoid loading sframe-channel in parallel with the
|
||||
// loading screen setup.
|
||||
var done = waitFor();
|
||||
var onMsg = function (msg) {
|
||||
var data = JSON.parse(msg.data);
|
||||
if (data.q !== 'READY') { return; }
|
||||
window.removeEventListener('message', onMsg);
|
||||
var _done = done;
|
||||
done = function () { };
|
||||
_done();
|
||||
};
|
||||
window.addEventListener('message', onMsg);
|
||||
}).nThen(function (/*waitFor*/) {
|
||||
SFCommonO.start({
|
||||
type: 'oo'
|
||||
});
|
||||
});
|
||||
});
|
After Width: | Height: | Size: 477 KiB |
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<ul>
|
||||
<li><a href="document/">Text</a></li>
|
||||
<li><a href="spreadsheet/">Calc</a></li>
|
||||
<li><a href="presentation/">Presentation</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
<link rel="icon" type="image/png"
|
||||
href="/customize/main-favicon.png"
|
||||
data-main-favicon="/customize/main-favicon.png"
|
||||
data-alt-favicon="/customize/alt-favicon.png"
|
||||
id="favicon" />
|
||||
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="/customize/main.css" />
|
||||
<style>
|
||||
html, body{
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
#editor {
|
||||
position: absolute;
|
||||
margin-top: 70px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
background-color: lightgrey;
|
||||
}
|
||||
#ooframe {
|
||||
position:absolute;
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
overflow:hidden;
|
||||
}
|
||||
.cryptpad-toolbar {
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="toolbar" class="toolbar-container"></div>
|
||||
|
||||
<div id="editor">
|
||||
<iframe id="ooframe" src="presentation.html" width="100%" height="100%">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div id="loading">
|
||||
<div class="loadingContainer">
|
||||
<img class="cryptofist" src="/customize/cryptofist_small.png" />
|
||||
<div class="spinnerContainer">
|
||||
<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>
|
||||
</div>
|
||||
<p data-localization="loading"></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,495 @@
|
||||
require.config({ paths: {
|
||||
'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify'
|
||||
}});
|
||||
|
||||
define([
|
||||
'/api/config?cb=' + Math.random().toString(16).substring(2),
|
||||
'/bower_components/chainpad-netflux/chainpad-netflux.js',
|
||||
'/bower_components/hyperjson/hyperjson.js',
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
'/common/toolbar.js',
|
||||
'/bower_components/textpatcher/TextPatcher.amd.js',
|
||||
'json.sortify',
|
||||
'/bower_components/chainpad-json-validator/json-ot.js',
|
||||
'/common/cryptpad-common.js',
|
||||
'/bower_components/secure-fabric.js/dist/fabric.min.js',
|
||||
'/bower_components/jquery/dist/jquery.min.js',
|
||||
'/bower_components/file-saver/FileSaver.min.js',
|
||||
'/bower_components/diff-dom/diffDOM.js',
|
||||
], function (Config, Realtime, Hyperjson, Crypto, Toolbar, TextPatcher, JSONSortify, JsonOT, Cryptpad) {
|
||||
var saveAs = window.saveAs;
|
||||
var Messages = Cryptpad.Messages;
|
||||
|
||||
var module = window.APP = { };
|
||||
var $ = module.$ = window.jQuery;
|
||||
var Fabric = module.Fabric = window.fabric;
|
||||
window.Hyperjson = Hyperjson;
|
||||
|
||||
$(function () {
|
||||
var DiffDom = window.diffDOM;
|
||||
Cryptpad.addLoadingScreen();
|
||||
var onConnectError = function (info) {
|
||||
Cryptpad.errorLoadingScreen(Messages.websocketError);
|
||||
};
|
||||
|
||||
var emitResize = module.emitResize = function () {
|
||||
var cw = $('#ooframe')[0].contentWindow;
|
||||
|
||||
var evt = cw.document.createEvent('UIEvents');
|
||||
evt.initUIEvent('resize', true, false, cw, 0);
|
||||
cw.dispatchEvent(evt);
|
||||
};
|
||||
|
||||
var toolbar;
|
||||
|
||||
var secret = Cryptpad.getSecrets();
|
||||
readOnly = secret.keys && !secret.keys.editKeyStr;
|
||||
ooReady = false;
|
||||
firstRemote = false;
|
||||
|
||||
if (!secret.keys) {
|
||||
secret.keys = secret.key;
|
||||
}
|
||||
|
||||
var andThen = function () {
|
||||
|
||||
var saveToServer = module.saveToServer = function () {
|
||||
config.onLocal();
|
||||
}
|
||||
|
||||
var callRemote = module.callRemote = function() {
|
||||
config.onRemote();
|
||||
}
|
||||
|
||||
var saveDocument = module.saveDocument = function () {
|
||||
var defaultName = "text.oot";
|
||||
Cryptpad.prompt(Messages.exportPrompt, defaultName, function (filename) {
|
||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||
console.log("In saveDocument");
|
||||
var content = window.frames[0].frames[0].editor.asc_nativeGetFile();
|
||||
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, filename);
|
||||
});
|
||||
};
|
||||
|
||||
var loadDocument = module.loadDocument = function (content, file) {
|
||||
// console.log("Read " + content);
|
||||
console.log("In loadDocument");
|
||||
var openResult = {data: content, url: "http://localhost:3000/onlyoffice/"};
|
||||
window.frames[0].frames[0].AscCommon.History.TurnOff();
|
||||
window.frames[0].frames[0].editor.openDocument(openResult);
|
||||
};
|
||||
|
||||
initializing = true;
|
||||
|
||||
var $bar = $('#toolbar');
|
||||
var parsedHash = Cryptpad.parsePadUrl(window.location.href);
|
||||
var defaultName = Cryptpad.getDefaultName(parsedHash);
|
||||
var isHistoryMode = false;
|
||||
var userData = module.userData = {}; // List of pretty name of all users (mapped with their server ID)
|
||||
var userList; // List of users still connected to the channel (server IDs)
|
||||
var addToUserData = function(data) {
|
||||
var users = module.users;
|
||||
for (var attrname in data) { userData[attrname] = data[attrname]; }
|
||||
|
||||
if (users && users.length) {
|
||||
for (var userKey in userData) {
|
||||
if (users.indexOf(userKey) === -1) {
|
||||
delete userData[userKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(userList && typeof userList.onChange === "function") {
|
||||
userList.onChange(userData);
|
||||
}
|
||||
};
|
||||
|
||||
var myData = {};
|
||||
var myUserName = ''; // My "pretty name"
|
||||
var myID; // My server ID
|
||||
|
||||
var setMyID = function(info) {
|
||||
myID = info.myID || null;
|
||||
myUserName = myID;
|
||||
};
|
||||
|
||||
var config = module.config = {
|
||||
initialState: '{}',
|
||||
websocketURL: Cryptpad.getWebsocketURL(),
|
||||
validateKey: secret.keys.validateKey,
|
||||
readOnly: readOnly,
|
||||
channel: secret.channel,
|
||||
crypto: Crypto.createEncryptor(secret.keys),
|
||||
setMyID: setMyID,
|
||||
transformFunction: JsonOT.transform,
|
||||
};
|
||||
|
||||
var suggestName = function (fallback) {
|
||||
if (document.title === defaultName) {
|
||||
return fallback || "";
|
||||
} else {
|
||||
return document.title || defaultName;
|
||||
}
|
||||
};
|
||||
|
||||
var renameCb = function (err, title) {
|
||||
if (err) { return; }
|
||||
document.title = title;
|
||||
config.onLocal();
|
||||
};
|
||||
|
||||
var editHash;
|
||||
var onInit = config.onInit = function (info) {
|
||||
userList = info.userList;
|
||||
var config = {
|
||||
displayed: ['useradmin', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'],
|
||||
userData: userData,
|
||||
readOnly: readOnly,
|
||||
share: {
|
||||
secret: secret,
|
||||
channel: info.channel
|
||||
},
|
||||
ifrw: window,
|
||||
title: {
|
||||
onRename: renameCb,
|
||||
defaultName: defaultName,
|
||||
suggestName: suggestName
|
||||
},
|
||||
common: Cryptpad
|
||||
};
|
||||
if (readOnly) {delete config.changeNameID; }
|
||||
toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, userList, config);
|
||||
|
||||
var $rightside = $bar.find('.' + Toolbar.constants.rightside);
|
||||
|
||||
/* add a history button */
|
||||
var histConfig = {};
|
||||
histConfig.onRender = function (val) {
|
||||
if (typeof val === "undefined") { return; }
|
||||
try {
|
||||
console.log("History render: " + val);
|
||||
} catch (e) {
|
||||
// Probably a parse error
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
histConfig.onClose = function () {
|
||||
// Close button clicked
|
||||
setHistory(false, true);
|
||||
jQuery("#editor")[0].style="margin-top: 70px;";
|
||||
|
||||
};
|
||||
histConfig.onRevert = function () {
|
||||
// Revert button clicked
|
||||
setHistory(false, false);
|
||||
onLocal();
|
||||
onRemote();
|
||||
};
|
||||
histConfig.onReady = function () {
|
||||
// Called when the history is loaded and the UI displayed
|
||||
setHistory(true);
|
||||
jQuery("#editor")[0].style="margin-top: 100px;";
|
||||
};
|
||||
histConfig.$toolbar = $bar;
|
||||
var $hist = Cryptpad.createButton('history', true, {histConfig: histConfig});
|
||||
$rightside.append($hist);
|
||||
|
||||
var $export = Cryptpad.createButton('export', true, {}, saveDocument);
|
||||
$rightside.append($export);
|
||||
var $import = Cryptpad.createButton('import', true, {}, loadDocument);
|
||||
$rightside.append($import);
|
||||
var $save = Cryptpad.createButton('save', true, {}, saveToServer);
|
||||
$save.click(function () {
|
||||
saveToServer();
|
||||
});
|
||||
$rightside.append($save);
|
||||
var $remote = Cryptpad.createButton('remote', true, {}, callRemote);
|
||||
$remote.click(function () {
|
||||
callRemote();
|
||||
});
|
||||
$rightside.append($remote);
|
||||
|
||||
var editHash;
|
||||
var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys);
|
||||
|
||||
if (!readOnly) {
|
||||
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
|
||||
}
|
||||
if (!readOnly) { Cryptpad.replaceHash(editHash); }
|
||||
};
|
||||
|
||||
// used for debugging, feel free to remove
|
||||
var Catch = function (f) {
|
||||
return function () {
|
||||
try {
|
||||
f();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var setHistory = function (bool, update) {
|
||||
isHistoryMode = bool;
|
||||
// setEditable(!bool);
|
||||
if (!bool && update) {
|
||||
config.onRemote();
|
||||
}
|
||||
};
|
||||
|
||||
var updateTitle = function (newTitle) {
|
||||
if (newTitle === document.title) { return; }
|
||||
// Change the title now, and set it back to the old value if there is an error
|
||||
var oldTitle = document.title;
|
||||
document.title = newTitle;
|
||||
Cryptpad.renamePad(newTitle, function (err, data) {
|
||||
if (err) {
|
||||
console.log("Couldn't set pad title");
|
||||
console.error(err);
|
||||
document.title = oldTitle;
|
||||
return;
|
||||
}
|
||||
document.title = data;
|
||||
$bar.find('.' + Toolbar.constants.title).find('span.title').text(data);
|
||||
$bar.find('.' + Toolbar.constants.title).find('input').val(data);
|
||||
});
|
||||
};
|
||||
|
||||
var updateDefaultTitle = function (defaultTitle) {
|
||||
defaultName = defaultTitle;
|
||||
$bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName);
|
||||
};
|
||||
|
||||
var updateMetadata = function(shjson) {
|
||||
// Extract the user list (metadata) from the hyperjson
|
||||
var json = (shjson === "") ? "" : JSON.parse(shjson);
|
||||
var titleUpdated = false;
|
||||
if (json && json.metadata) {
|
||||
if (json.metadata.users) {
|
||||
var userData = json.metadata.users;
|
||||
// Update the local user data
|
||||
addToUserData(userData);
|
||||
}
|
||||
if (json.metadata.defaultTitle) {
|
||||
updateDefaultTitle(json.metadata.defaultTitle);
|
||||
}
|
||||
if (typeof json.metadata.title !== "undefined") {
|
||||
updateTitle(json.metadata.title || defaultName);
|
||||
titleUpdated = true;
|
||||
}
|
||||
}
|
||||
if (!titleUpdated) {
|
||||
updateTitle(defaultName);
|
||||
}
|
||||
};
|
||||
|
||||
var hjson2domstring = function(hjson) {
|
||||
var userDocStateDom = hjsonToDom(JSON.parse(hjson));
|
||||
var tmp = document.createElement("div");
|
||||
tmp.appendChild(userDocStateDom);
|
||||
return tmp.innerHTML;
|
||||
};
|
||||
|
||||
var onRemoteInit = config.onRemoteInit = Catch(function() {
|
||||
console.log("In onRemoteInit");
|
||||
ooReady = true;
|
||||
});
|
||||
|
||||
var onRemote = config.onRemote = Catch(function () {
|
||||
console.log("In onRemote");
|
||||
if (initializing) { return; }
|
||||
if (isHistoryMode) { return; }
|
||||
|
||||
// force readonly to prevent interlacing
|
||||
readOnly = true;
|
||||
|
||||
try {
|
||||
if (window.frames[0].frames[0]==null || window.frames[0].frames[0].editor==null) {
|
||||
console.log("Cannot access editor");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("In onRemote sync");
|
||||
var previousData = window.frames[0].frames[0].editor.asc_nativeGetFile();
|
||||
var userDoc = module.realtime.getUserDoc();
|
||||
|
||||
// console.log("Current data " + previousData);
|
||||
|
||||
updateMetadata(userDoc);
|
||||
var json = JSON.parse(userDoc);
|
||||
var remoteDoc = json.content;
|
||||
if (remoteDoc!=previousData) {
|
||||
console.log("Remote content is different")
|
||||
// console.log("Remote content hjson: " + remoteDoc);
|
||||
if (ooReady) {
|
||||
if (remoteDoc)
|
||||
loadDocument(remoteDoc);
|
||||
firstRemote = true;
|
||||
}
|
||||
} else {
|
||||
console.log("Data is unchanged");
|
||||
firstRemote = true;
|
||||
}
|
||||
|
||||
readOnly = false;
|
||||
} catch (e) {
|
||||
console.log("Exception: " + e);
|
||||
throw e;
|
||||
} finally {
|
||||
readOnly = false;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
var diffOptions = {
|
||||
preDiffApply: function (info) {
|
||||
},
|
||||
postDiffApply : function(info) {
|
||||
}
|
||||
};
|
||||
|
||||
var DD = new DiffDom(diffOptions);
|
||||
|
||||
// apply patches, and try not to lose the cursor in the process!
|
||||
var applyHjson = function (shjson, domElement) {
|
||||
var userDocStateDom = hjsonToDom(JSON.parse(shjson));
|
||||
|
||||
if (!readOnly && !initializing) {
|
||||
userDocStateDom.setAttribute("contenteditable", "true"); // lol wtf
|
||||
}
|
||||
var patch = (DD).diff(domElement, userDocStateDom);
|
||||
(DD).apply(domElement, patch);
|
||||
};
|
||||
|
||||
var stringify = function (obj) {
|
||||
return JSONSortify(obj);
|
||||
};
|
||||
|
||||
var hjsonToDom = function (H) {
|
||||
var dom = Hyperjson.toDOM(H);
|
||||
return dom;
|
||||
};
|
||||
|
||||
|
||||
var stringifyInner = function (textValue) {
|
||||
var obj = {
|
||||
content: textValue,
|
||||
metadata: {
|
||||
users: userData,
|
||||
defaultTitle: defaultName
|
||||
}
|
||||
};
|
||||
if (!initializing) {
|
||||
obj.metadata.title = document.title;
|
||||
}
|
||||
// stringify the json and send it into chainpad
|
||||
return JSONSortify(obj);
|
||||
};
|
||||
|
||||
var onLocal = config.onLocal = Catch(function () {
|
||||
console.log("In onLocal");
|
||||
if (initializing) { return; }
|
||||
if (isHistoryMode) { return; }
|
||||
if (readOnly) { return; }
|
||||
if (!ooReady) { return; }
|
||||
|
||||
if (!firstRemote) {
|
||||
console.log("First remote");
|
||||
onRemote();
|
||||
if (firstRemote) {
|
||||
console.log("First remote success");
|
||||
} else {
|
||||
console.log("First remote failure");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (window.frames[0].frames[0]==null || window.frames[0].frames[0].editor==null)
|
||||
return;
|
||||
|
||||
console.log("In onLocal sync");
|
||||
var data = window.frames[0].frames[0].editor.asc_nativeGetFile();
|
||||
var content = stringifyInner(data);
|
||||
module.patchText(content);
|
||||
});
|
||||
|
||||
var setName = module.setName = function (newName) {
|
||||
if (typeof(newName) !== 'string') { return; }
|
||||
var myUserNameTemp = newName.trim();
|
||||
if(newName.trim().length > 32) {
|
||||
myUserNameTemp = myUserNameTemp.substr(0, 32);
|
||||
}
|
||||
myUserName = myUserNameTemp;
|
||||
myData[myID] = {
|
||||
name: myUserName,
|
||||
uid: Cryptpad.getUid(),
|
||||
};
|
||||
addToUserData(myData);
|
||||
Cryptpad.setAttribute('username', myUserName, function (err, data) {
|
||||
if (err) {
|
||||
console.log("Couldn't set username");
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
onLocal();
|
||||
});
|
||||
};
|
||||
|
||||
var onReady = config.onReady = function (info) {
|
||||
var realtime = module.realtime = info.realtime;
|
||||
module.patchText = TextPatcher.create({
|
||||
realtime: realtime
|
||||
});
|
||||
|
||||
Cryptpad.removeLoadingScreen();
|
||||
// setEditable(true);
|
||||
initializing = false;
|
||||
onRemote();
|
||||
Cryptpad.getLastName(function (err, lastName) {
|
||||
if (err) {
|
||||
console.log("Could not get previous name");
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
// Update the toolbar list:
|
||||
// Add the current user in the metadata if he has edit rights
|
||||
if (readOnly) { return; }
|
||||
if (typeof(lastName) === 'string') {
|
||||
setName(lastName);
|
||||
} else {
|
||||
myData[myID] = {
|
||||
name: "",
|
||||
uid: Cryptpad.getUid(),
|
||||
};
|
||||
addToUserData(myData);
|
||||
onLocal();
|
||||
// module.$userNameButton.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var onAbort = config.onAbort = function (info) {
|
||||
// setEditable(false);
|
||||
window.alert("Server Connection Lost");
|
||||
|
||||
if (window.confirm("Would you like to save your image?")) {
|
||||
saveImage();
|
||||
}
|
||||
};
|
||||
|
||||
var rt = Realtime.start(config);
|
||||
};
|
||||
|
||||
Cryptpad.ready(function (err, env) {
|
||||
andThen();
|
||||
});
|
||||
Cryptpad.onError(function (info) {
|
||||
if (info) {
|
||||
onConnectError();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@ -0,0 +1,31 @@
|
||||
<html>
|
||||
<body>
|
||||
<div id="placeholder"></div>
|
||||
<script type="text/javascript" src="/onlyoffice/web-apps/apps/api/documents/api.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
config = {
|
||||
"document": {
|
||||
"fileType": "pptx",
|
||||
"key": "Khirz6zTPdfd7",
|
||||
"title": "test.pptx",
|
||||
"url": "http://localhost:3000/onlyoffice/test.pptx"
|
||||
},
|
||||
"documentType": "presentation",
|
||||
"editorConfig": {
|
||||
"user": {
|
||||
"id": "c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
||||
"name": "John Smith"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"onDocumentStateChange": function(evt) { console.log("in change"); window.top.APP.config.onLocal(); },
|
||||
"onReady": function(evt) { console.log("in onReady"); window.top.APP.config.onRemoteInit(); }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var docEditor = new DocsAPI.DocEditor("placeholder", config);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 902 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 540 KiB |