Clean onlyoffice files
parent
db71fe5bf8
commit
9ba912d953
@ -1,10 +0,0 @@
|
||||
<!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>
|
@ -1,60 +0,0 @@
|
||||
<!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>
|
@ -1,495 +0,0 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
<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>
|
File diff suppressed because one or more lines are too long
@ -1,60 +0,0 @@
|
||||
<!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="spreadsheet.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>
|
@ -1,496 +0,0 @@
|
||||
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();
|
||||
var readOnly = secret.keys && !secret.keys.editKeyStr;
|
||||
var ooReady = false;
|
||||
var 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);
|
||||
window.frames[0].frames[0].AscCommon.g_inputContext = null;
|
||||
window.frames[0].frames[0].editor.DocumentLoadComplete = false;
|
||||
window.frames[0].frames[0].editor.IsSendDocumentLoadCompleate = false;
|
||||
window.frames[0].frames[0].editor.openDocument(content);
|
||||
window.frames[0].frames[0].editor.asc_Resize()
|
||||
// window.frames[0].frames[0].editor.SetTextBoxInputMode(true);
|
||||
|
||||
};
|
||||
|
||||
var 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) {
|
||||
} 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();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
<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": "xlsx",
|
||||
"key": "Khirz6zTPdfd7",
|
||||
"title": "test.xlsx",
|
||||
"url": "http://localhost:3000/onlyoffice/xlsx.docx"
|
||||
},
|
||||
"documentType": "spreadsheet",
|
||||
"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>
|
@ -1 +0,0 @@
|
||||
XLSY;v2;3547;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
|
Loading…
Reference in New Issue