dab5afac90
Add CloseSession button. Also improve spacing of elements. Signed-off-by: Méven Car <meven.car@collabora.com> Change-Id: I9999654f9d53d44016eeb0ea587cf3f61b000471
639 lines
22 KiB
HTML
639 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>
|