collabora-online/browser/html/framed.doc.html

640 lines
22 KiB
HTML

<!DOCTYPE html>
<!-- Proof of concept of running cool.html in an iframe. Also
shows how to, from outside the iframe, invoke Python scripting in
the underlying LibreOffice instance that manipulates the document
being edited.
This demonstrates using the Python InsertText.py and Capitalise.py
scripts from javascript across iframes.
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Online Editor</title>
<style>
:root {
font-family: "sans-serif";
}
.alert {
font-size: large;
padding: 20px;
background-color: #f44336;
color: white;
margin-bottom: 15px;
}
.framed {
padding: 15px;
border: 1px black dashed;
border-radius: 6px;
}
.vbox {
display: flex;
flex-direction: column;
gap: 0.5em;
}
.hbox {
display: flex;
flex-direction: row;
gap: 0.5em;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 0.5em;
gap: 0.5em;
}
.spaced {
gap: 15px;
grid-gap: 15px;
}
h3 {
margin: 0.2em 0px;
}
pre {
margin: 0px;
}
</style>
<script>
function post(msg) {
window.frames[0].postMessage(JSON.stringify(msg), '*');
}
function sendBoldUNOCommand() {
post({'MessageId': 'Send_UNO_Command',
'Values': { 'Command': '.uno:Bold' }
});
}
function sendInsertBookMarkUNOCommand() {
post({'MessageId': 'Send_UNO_Command',
'Values': {
'Command': '.uno:InsertBookmark',
'Args': {
Bookmark: {
type: 'string',
value: 'Test Insert BookMark'
},
BookmarkText: {
type: 'string',
value: 'Text of the Test Insert BookMark'
}
}
}
});
}
function insertText(text) {
post({'MessageId': 'CallPythonScript',
'SendTime': Date.now(),
'ScriptFile': 'InsertText.py',
'Function': 'InsertText',
'Values': { 'text': {'type': 'string', 'value': text}}
});
}
function capitalize() {
post({'MessageId': 'CallPythonScript',
'SendTime': Date.now(),
'ScriptFile': 'Capitalise.py',
'Function': 'capitalisePython',
'Values': null
});
}
function save() {
post({'MessageId': 'Action_Save',
'Values': { 'Notify': true, 'ExtendedData': 'CustomFlag=Custom Value;AnotherFlag=AnotherValue' }
});
}
function closeDocument() {
post({'MessageId': 'Action_Close',
'Values': null
});
}
function closeSession() {
post({'MessageId': 'Close_Session',
'Values': null
});
}
function fullscreenDocument() {
post({'MessageId': 'Action_Fullscreen',
'Values': null
});
}
function startPresentation() {
post({'MessageId': 'Action_FullscreenPresentation',
'Values': null
});
}
function exportAsHtml() {
post({'MessageId': 'Action_Export',
'Values': { 'Format': 'html', }
});
}
function exportAsPdfWithNotify() {
post({'MessageId': 'Action_Export',
'Values': { 'Format': 'pdf', Notify: true }
});
}
function getExportFormats() {
post({'MessageId': 'Get_Export_Formats',
'Values': null
});
}
function hide_commands(id) {
post({'MessageId': 'Hide_Menu_Item',
'Values': { 'id': id, }
});
post({'MessageId': 'Hide_Button',
'Values': { 'id': id, }
});
}
function show_commands(id) {
post({'MessageId': 'Show_Menu_Item',
'Values': { 'id': id, }
});
post({'MessageId': 'Show_Button',
'Values': { 'id': id, }
});
}
function disable_default_uiaction(action, disable) {
post({'MessageId': 'Disable_Default_UIAction',
'Values': { 'action': action, 'disable': disable }
});
}
function ShowSave(show) {
if (show) {
show_commands('save');
show_commands('file-save');
} else {
hide_commands('save');
hide_commands('file-save');
}
}
function HintOnscreenKeyboard(hint) {
post({'MessageId': hint ? 'Hint_OnscreenKeyboard' : 'Hint_NoOnscreenKeyboard',
'Values': null
});
}
function ShowMenubar(visible) {
var messageId = visible ? 'Show_Menubar' : 'Hide_Menubar';
post({'MessageId': messageId});
}
function ShowRuler(visible) {
var messageId = visible ? 'Show_Ruler' : 'Hide_Ruler';
post({'MessageId': messageId});
}
function ShowStatusBar(visible) {
var messageId = visible ? 'Show_StatusBar' : 'Hide_StatusBar';
post({'MessageId': messageId});
}
function ShowInsertButton() {
post({'MessageId': 'Insert_Button',
'Values': { 'id': 'Save', 'imgurl': 'images/lc_save.svg', 'hint': '', 'mobile': false, 'label': 'Show additional btns via Insert_Button', 'insertBefore': 'Save', 'unoCommand': '.uno:Save'}
});
}
function ShowNotebookbar(notebookbar) {
var value = notebookbar ? 'notebookbar' : 'classic';
post({'MessageId': 'Action_ChangeUIMode',
'Values': {'Mode': value}});
}
function CollapseNotebookbar(collapse) {
post({'MessageId': collapse ? 'Collapse_Notebookbar' : 'Extend_Notebookbar',
'Values': null
});
}
// Wrap the message execution to catch exceptions
function executeMessage() {
try {
Execute(
document.getElementById('execute-message').value,
JSON.parse(document.getElementById('execute-param').value)
);
} catch(e) {
console.error("Execute message error:", e);
}
}
function Execute(messageId, values) {
post({'MessageId': messageId, 'Values': values});
}
function reset_access_token(accesstoken) {
post({'MessageId': 'Reset_Access_Token',
'Values': { 'token': accesstoken, }
});
}
function GetUserState() {
post({'MessageId': 'Get_User_State',
'Values': null
});
}
function DisplayUserState(msg) {
var display = document.getElementById("DisplayUserState");
display.querySelector("#UserState_State").textContent = msg.Values.State;
display.querySelector("#UserState_Elapsed").textContent = msg.Values.Elapsed;
}
// This function is invoked when the iframe posts a message back.
function receiveMessage(event) {
console.log('==== framed.doc.html receiveMessage: ' + event.data);
var msg = JSON.parse(event.data);
if (!msg) {
return;
}
let messageOut = document.getElementById("messages");
messageOut.textContent = messageOut.textContent + JSON.stringify(msg) + "\n";
if (msg.MessageId == 'App_LoadingStatus') {
if (msg.Values) {
if (msg.Values.Status == 'Document_Loaded') {
post({'MessageId': 'Host_PostmessageReady'});
}
}
} else if (msg.MessageId == 'Doc_ModifiedStatus') {
if (msg.Values) {
if (msg.Values.Modified == true) {
document.getElementById("ModifiedStatus").innerHTML = "Modified";
}
else {
document.getElementById("ModifiedStatus").innerHTML = "Saved";
}
}
} else if (msg.MessageId == 'Get_User_State_Resp') {
DisplayUserState(msg);
} else if (msg.MessageId == 'Action_Save_Resp') {
if (msg.Values) {
if (msg.Values.success == true) {
document.getElementById("ModifiedStatus").innerHTML = "Saved";
} else {
document.getElementById("ModifiedStatus").innerHTML = "Error during save";
}
}
} else if (msg.MessageId === 'UI_Mention') {
var dummyUserDatabase = [ {
username:'Abigail',
profile: 'Abigail profile link'
},
{
username: 'Alexandra',
profile: 'Alexandra profile link'
},
{
username: 'Alison',
profile: 'Alison profile link'
},
{
username: 'Amanda',
profile: 'Amanda profile link'
},
{
username: 'Amelia',
profile: 'Amelia profile link'
},
{
username: 'Amy',
profile: 'Amy profile link'
},
{
username: 'Andrea',
profile: 'Andrea profile link'
},
{
username: 'Angela',
profile: 'Angela profile link'
},
{
username: 'Anna',
profile: 'Anna profile link'
},
{
username: 'Anne',
profile: 'Anne profile link'
},
{
username: 'Audrey',
profile: 'Audrey profile link'
},
{
username: 'Ava',
profile: 'Ava profile link'
},
{
username: 'Bella',
profile: 'Bella profile link'
},
{
username: 'Bernadette',
profile: 'Bernadette profile link'
},
{
username: 'Carol',
profile: 'Carol profile link'
},
{
username: 'Caroline',
profile: 'Caroline profile link'
},
{
username: 'Carolyn',
profile: 'Carolyn profile link'
},
{
username: 'xyz abc',
profile: 'xyz abc profile link'
} ];
if (msg.Values) {
var type = msg.Values.type;
var text = msg.Values.text;
var users = [];
dummyUserDatabase.forEach(element => {
if (element.username.includes(text))
users.push(element);
});
if (type === 'autocomplete')
{
setTimeout(post, 0,
{
'MessageId': 'Action_Mention',
'SendTime': Date.now(),
'Values': {
'list': users,
}
});
}
}
} else if (msg.MessageId == 'Get_Export_Formats_Resp') {
if (msg.Values) {
alert(JSON.stringify(msg.Values));
} else {
alert('Response is empty');
}
}
}
// 'main' code of this <script> block, run when page is being
// rendered. Install the message listener.
window.addEventListener("message", receiveMessage, false);
var frameUrl = new URL(window.location);
frameUrl.pathname = frameUrl.pathname.substr(0, window.location.pathname.lastIndexOf('/') + 1) + 'cool.html';
frameUrl.searchParams.append('NotWOPIButIframe', 'true');
function startCool(url, file_path) {
var coolUrl = new URL(url);
if (file_path) {
coolUrl.searchParams.set('file_path', file_path);
}
var iframe = document.getElementById('frame');
iframe.src = coolUrl.href;
link.href = coolUrl.href;
}
// Select the app with extension.
function selectApp(ext) {
switch (ext) {
case 'odt':
case 'ods':
case 'odp':
case 'odg':
var params = frameUrl.searchParams;
var file_path = params.get('file_path');
file_path = file_path.substr(0, file_path.length - 3) + ext;
startCool(frameUrl, file_path)
break;
default:
console.error('Invalid app ', ext);
}
}
</script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="usage" class="alert" style="display:none">
<h2>Usage</h2>
<p>
Load this page via https or http, depending on whether SSL is enabled or not, from the Online server directly.</br>
The document to load must be given as a query parameter called file_path. The document can be any accessible URL, including on disk, via file://.
</p>
<h4>Example</h4>
<p>
http://localhost:9980/browser/dist/framed.doc.html?file_path=file:///path/to/document/hello-world.odt
</p>
</div>
<div id="post-message-test-harness" class="vbox">
<h2>PostMessage test harness</h2>
<div class="grid spaced">
<div class="vbox framed">
<h3>Run python scripts</h3>
<form id="insert-text-form" class="vbox">
<label for="fname"><b>InsertText.py</b>: inserts text into the document</label>
<textarea name="source" value="" rows="5" cols="50">Type your text and press Insert text</textarea>
<div>
<button onclick="insertText(document.forms['insert-text-form'].elements['source'].value); return false;">Insert text</button>
</div>
</form>
<form id="insert-text-form" class="vbox">
<label for="fname"><b>Capitalize.py</b>: capitalize selected text in the document</label>
<div>
<button onclick="capitalize(); return false;">Capitalize selected text</button>
</div>
</form>
</div>
<div class="vbox framed">
<h3>Various other messages to post</h3>
<div class="grid">
<button onclick="save(); return false;">Save</button>
<div></div>
<button onclick="closeDocument(); return false;">Close</button>
<button onclick="closeSession(); return false;">Close Session</button>
<button onclick="fullscreenDocument(); return false;">Fullscreen</button>
<button onclick="startPresentation(); return false;">Start presentation</button>
<button onclick="exportAsHtml(); return false;">Export as HTML</button>
<button onclick="exportAsPdfWithNotify(); return false;">Export as PDF with Notify set</button>
<button onclick="getExportFormats(); return false;">Get export formats</button>
<div></div>
<button onclick="ShowSave(false); return false;">Hide Save Commands</button>
<button onclick="ShowSave(true); return false;">Show Save Commands</button>
<button onclick="hide_commands('print'); return false;">Hide Print Commands</button>
<button onclick="show_commands('print'); return false;">Show Print Commands</button>
<button onclick="disable_default_uiaction('UI_Save', true); return false;">Disable default save action</button>
<button onclick="disable_default_uiaction('UI_Save', false); return false;">Enable default save action</button>
<button onclick="HintOnscreenKeyboard(true); return false;">Hint that there is an onscreen keyboard</button>
<button onclick="HintOnscreenKeyboard(false); return false;">Hint that there is not an onscreen keyboard</button>
</div>
</div>
<form class="vbox framed">
<h3>New Access-Token</h3>
<textarea name="new-access-token" id="new-access-token" value="" rows="1" cols="30">123456789AA</textarea>
<div>
<button onclick="reset_access_token(document.getElementById('new-access-token').value); return false;">Reset Access-Token</button>
</div>
<h3>User State</h3>
<div class="hbox">
<button onclick="GetUserState(); return false;">Get User State</button>
<div id="DisplayUserState">
<p>State: <span id="UserState_State">unknown</span>
Elapsed: <span id="UserState_Elapsed">0</span> sec.</p>
</div>
</div>
</form>
<div class="vbox framed">
<h3>Send a message</h3>
<form>
<div class="hbox">
<div>
<label for="execute-message"><b>Message</b>: </label><br>
<input type="text" name="execute-message" id="execute-message" />
</div>
<div>
<label for="execute-param"><b>Values</b>: </label>
<p>This is the JSON format 'Values'.</p>
<textarea name="execute-param" id="execute-param">{}</textarea>
</div>
</div>
<button onclick="executeMessage(); return false;">Execute</button>
</form>
</div>
</div>
<div class="framed hbox">
<div class="vbox">
<h3>Messages from editor</h3>
<pre id="messages"></pre>
</div>
</div>
<div class="vbox">
<h3>Modified Status: <span id="ModifiedStatus">Saved</span></h3>
</div>
<div class="grid spaced">
<div class="framed">
<h3>UI modification</h3>
<div class="hbox">
<div class="vbox">
<button onclick="ShowMenubar(false); return false;">Hide Menubar</button>
<button onclick="ShowMenubar(true); return false;">Show Menubar</button>
</div>
<div class="vbox">
<button onclick="ShowInsertButton(); return false;" title="via Insert_Button">Insert custom button</button>
</div>
<div class="vbox">
<button onclick="ShowNotebookbar(false); return false;">Compact Toolbar</button>
<button onclick="ShowNotebookbar(true); return false;">Tabbed Toolbar</button>
</div>
<div class="vbox">
<button onclick="CollapseNotebookbar(true); return false;">Collapse Tabbed Toolbar</button>
<button onclick="CollapseNotebookbar(false); return false;">Extend Tabbed Toolbar</button>
</div>
<div class="vbox">
<button onclick="ShowStatusBar(false); return false;">Hide Status Bar</button>
<button onclick="ShowStatusBar(true); return false;">Show Status Bar</button>
</div>
<div class="vbox">
<button onclick="ShowRuler(false); return false;">Hide Ruler</button>
<button onclick="ShowRuler(true); return false;">Show Ruler</button>
</div>
</div>
</div>
<div class="vbox framed">
<h3>Send UNO Commands</h3>
<div class="hbox">
<button onclick="sendBoldUNOCommand(); return false;">Send Bold UNO Command (an example without args)</button>
<button onclick="sendInsertBookMarkUNOCommand(); return false;">Send InsertBookmark UNO Command (an example with args)</button>
</div>
</div>
</div>
<div class="vbox">
<h3>Document type</h3>
</div>
<div class="vbox framed">
<div class="hbox">
<button onclick="selectApp('odt');">Writer</button>
<button onclick="selectApp('ods');">Calc</button>
<button onclick="selectApp('odp');">Impress</button>
<button onclick="selectApp('odg');">Draw</button>
</div>
</div>
<h3>Document frame</h3>
<h4>If the frame fails to load click <a id="link">here and accept security bits</a></h4>
<h4>If the frame still fails to load ensure you have <code>localhost:*</code> included in your <code>net.frame_ancestors</code> in coolwsd.xml</h4>
<div class="vbox">
<iframe id="frame" height="1000"></iframe>
</div>
<script>
if (document.location.protocol == 'file:' || window.location.search == '') {
document.getElementById("usage").style.display = "block";
alert('Incorrect usage, please follow the instructions at the top of this page.');
}
var url = new URL(window.location);
var params = url.searchParams;
startCool(frameUrl, params.get("file_path"));
</script>
</body>
</html>