mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-12-31 19:27:00 -06:00
9b202bb95e
* Typescript - Fix localization for screen picker & spellchecker modules * Typescript - Fix custom title bar menu item * Typescript - Updated screen picker unit tests * Typescript - Update appName place holder * Typescript - Add backward compatibility support for screen snippet * Typescript - Optimize and refactor code
614 lines
23 KiB
HTML
614 lines
23 KiB
HTML
<html>
|
|
<head>
|
|
<style>
|
|
table {
|
|
border-collapse: collapse;
|
|
border-spacing: 0;
|
|
}
|
|
table, th, td {
|
|
padding: 5px;
|
|
border: 1px solid black;
|
|
}
|
|
|
|
.yellow-dot {
|
|
height: 25px;
|
|
width: 25px;
|
|
background-color: yellow;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
}
|
|
|
|
.green-dot {
|
|
height: 25px;
|
|
width: 25px;
|
|
background-color: green;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
}
|
|
</style>
|
|
<link rel="stylesheet" href="download-manager.css">
|
|
</head>
|
|
<body>
|
|
<h1>Symphony Electron API Demo</h1>
|
|
<hr>
|
|
<p>Notifications:<p>
|
|
<button id='notf'>show notification</button>
|
|
<p>
|
|
<label for='title'>title:</label>
|
|
<input type='text' id='title' value='Notification Demo'/>
|
|
</p>
|
|
<p>
|
|
<label for='body'>body:</label>
|
|
<input type='text' id='body' value='Some message'/>
|
|
</p>
|
|
<p>
|
|
<label for='image'>image url:</label>
|
|
<input type='text' id='image' value='https://avatars0.githubusercontent.com/u/13243259?v=4&s=460'/>
|
|
</p>
|
|
<p>
|
|
<label for='company'>company:</label>
|
|
<input type='text' id='company' value='Symphony'/>
|
|
</p>
|
|
<p>
|
|
<label for='flash'>flash:</label>
|
|
<input type='checkbox' id='flash'/>
|
|
</p>
|
|
<p>
|
|
<label for='sticky'>sticky:</label>
|
|
<input type='checkbox' id='sticky'/>
|
|
</p>
|
|
<p>
|
|
<label for='color'>color:</label>
|
|
<input type='text' id='color' value='white'/>
|
|
</p>
|
|
<p>
|
|
<label for='tag'>tag:</label>
|
|
<input type='text' id='tag' value=''/>
|
|
</p>
|
|
<button id='open-config-win'>Open configure window</button>
|
|
<br>
|
|
<hr>
|
|
<textarea id="text-val" rows="4">Writes some thing to the file</textarea>
|
|
<br/>
|
|
<input type="button" id="download-file1" value="Download"/>
|
|
<input type="button" id="download-file2" value="Download"/>
|
|
<div id="footer"></div>
|
|
<br>
|
|
<hr>
|
|
<p>
|
|
Activity Detection:
|
|
<p>
|
|
<button id='activity-detection'>Init activity</button>
|
|
<span id='activity-status' class="green-dot"></span>
|
|
</p>
|
|
<br>
|
|
<hr>
|
|
<p>Change language:<p>
|
|
<select id="locale-select" name="locale">
|
|
<option value="en-US">en-US</option>
|
|
<option value="ja-JP">ja-JP</option>
|
|
<option value="fr-FR">fr-FR</option>
|
|
</select>
|
|
<button id="changeLocale">Submit</button>
|
|
<br>
|
|
<hr>
|
|
<p>Badge Count:<p>
|
|
<button id='inc-badge'>increment badge count</button>
|
|
<br>
|
|
<button id='clear-badge'>clear badge count</button>
|
|
<br>
|
|
<hr>
|
|
<p>Screen Snippet:</p>
|
|
<button id='snippet'>get snippet</button>
|
|
<p>snippet output:</p>
|
|
<image id='snippet-img'/>
|
|
|
|
<hr>
|
|
<p>Window activate:</p>
|
|
<button id='open-win'>open window</button>
|
|
|
|
<button id='bring-to-front'>bring window to front</button>
|
|
<button id='bring-to-front-without-focus'>bring to front without focus</button>
|
|
|
|
<hr>
|
|
<p>Get Media Sources:</p>
|
|
<button id='get-sources'>Open screen picker & screensharing indicator</button>
|
|
<br>
|
|
<video id='video' autoPlay loop muted style='max-width: 640px'></video>
|
|
|
|
<hr>
|
|
<p>Get Version Info:</p>
|
|
<button id='get-version'>get version info</button>
|
|
<br>
|
|
Version Info:
|
|
<table >
|
|
<tr>
|
|
<th>API Version</th>
|
|
<th>Container Identifier</th>
|
|
<th>Container Version</th>
|
|
<th>Build Number</th>
|
|
<th>Search Api Version</th>
|
|
</tr>
|
|
<tr>
|
|
<td id="api-version"></td>
|
|
<td id="container-identifier"></td>
|
|
<td id="container-ver"></td>
|
|
<td id="build-number"></td>
|
|
<td id="search-api-ver"></td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
<script>
|
|
|
|
window.name = 'main';
|
|
|
|
const apiCmds = {
|
|
isOnline: 'is-online',
|
|
getVersionInfo: 'get-version-info',
|
|
registerLogger: 'register-logger',
|
|
setBadgeCount: 'set-badge-count',
|
|
badgeDataUrl: 'badge-data-url',
|
|
activate: 'activate',
|
|
registerBoundsChange: 'register-bounds-change',
|
|
registerProtocolHandler: 'register-protocol-handler',
|
|
registerActivityDetection: 'register-activity-detection',
|
|
showNotificationSettings: 'show-notification-settings',
|
|
sanitize: 'sanitize',
|
|
bringToFront: 'bring-to-front',
|
|
openScreenPickerWindow: 'open-screen-picker-window',
|
|
popupMenu: 'popup-menu',
|
|
optimizeMemoryConsumption: 'optimize-memory-consumption',
|
|
optimizeMemoryRegister: 'optimize-memory-register',
|
|
setIsInMeeting: 'set-is-in-meeting',
|
|
setLocale: 'set-locale',
|
|
openScreenSnippet: 'open-screen-snippet',
|
|
keyPress: 'key-press',
|
|
closeWindow: 'close-window',
|
|
openScreenSharingIndicator: 'open-screen-sharing-indicator',
|
|
closeScreenSharingIndicator: 'close-screen-sharing-indicator',
|
|
downloadManagerAction: 'download-manager-action',
|
|
getMediaSource: 'get-media-source',
|
|
notification: 'notification',
|
|
closeNotification: 'close-notification',
|
|
};
|
|
let requestId = 0;
|
|
|
|
var openConfigWin = document.getElementById('open-config-win');
|
|
|
|
openConfigWin.addEventListener('click', function() {
|
|
if (window.ssf) {
|
|
ssf.showNotificationSettings();
|
|
} else {
|
|
postMessage(apiCmds.showNotificationSettings)
|
|
}
|
|
});
|
|
|
|
var notfEl = document.getElementById('notf');
|
|
var num = 0;
|
|
|
|
// note: notification will close when clicked
|
|
notfEl.addEventListener('click', function() {
|
|
var title = document.getElementById('title').value;
|
|
var body = document.getElementById('body').value;
|
|
var imageUrl = document.getElementById('image').value;
|
|
var shouldFlash = document.getElementById('flash').checked;
|
|
var shouldStick = document.getElementById('sticky').checked;
|
|
var color = document.getElementById('color').value;
|
|
var tag = document.getElementById('tag').value;
|
|
var company = document.getElementById('company').value;
|
|
|
|
num++;
|
|
|
|
var notf = {
|
|
id: num,
|
|
title,
|
|
body: (body + ' num=' + num + ' tag=' + tag),
|
|
image: imageUrl,
|
|
flash: shouldFlash,
|
|
color: color || 'white',
|
|
sticky: shouldStick,
|
|
data: {
|
|
hello: 'hello word'
|
|
},
|
|
tag: tag,
|
|
company: company,
|
|
method: 'notification',
|
|
};
|
|
|
|
window.postMessage({ method: 'notification', data: notf }, '*');
|
|
});
|
|
|
|
/**
|
|
* Badge Count
|
|
*/
|
|
let badgeCount = 0;
|
|
|
|
const incBadgeEl = document.getElementById('inc-badge');
|
|
incBadgeEl.addEventListener('click', () => {
|
|
badgeCount++;
|
|
if (window.ssf) {
|
|
ssf.setBadgeCount(badgeCount);
|
|
} else {
|
|
postMessage(apiCmds.setBadgeCount, badgeCount);
|
|
}
|
|
});
|
|
|
|
const clearBadgeCount = document.getElementById('clear-badge');
|
|
clearBadgeCount.addEventListener('click', () => {
|
|
badgeCount = 0;
|
|
if (window.ssf) {
|
|
ssf.setBadgeCount(0);
|
|
} else {
|
|
postMessage(apiCmds.setBadgeCount, 0);
|
|
}
|
|
});
|
|
|
|
const snippetButton = document.getElementById('snippet');
|
|
snippetButton.addEventListener('click', () => {
|
|
if (window.ssf) {
|
|
const gotSnippet = (rsp) => {
|
|
if (rsp) {
|
|
if (rsp.type && rsp.type === 'ERROR') {
|
|
// called when some error occurs during capture
|
|
alert('error getting snippet' + rsp.message);
|
|
} else if (rsp.data && rsp.type === 'image/png;base64') {
|
|
const dataUrl = 'data:' + rsp.type + ',' + rsp.data;
|
|
const img = document.getElementById('snippet-img');
|
|
img.src = dataUrl;
|
|
}
|
|
}
|
|
};
|
|
const screenSnippet = new window.ssf.ScreenSnippet();
|
|
screenSnippet.capture().then(gotSnippet).catch(gotSnippet);
|
|
} else {
|
|
postMessage(apiCmds.openScreenSnippet)
|
|
}
|
|
});
|
|
|
|
let win;
|
|
|
|
const openWinButton = document.getElementById('open-win');
|
|
openWinButton.addEventListener('click', () => {
|
|
win = window.open('win.html?x=100&y=100', 'test-window', 'height=800,width=400');
|
|
});
|
|
|
|
const front = document.getElementById('bring-to-front');
|
|
front.addEventListener('click', () => {
|
|
if (window.ssf) {
|
|
window.ssf.activate(win.name);
|
|
} else {
|
|
postMessage(apiCmds.activate, win.name);
|
|
}
|
|
});
|
|
|
|
const frontWithoutFocus = document.getElementById('bring-to-front-without-focus');
|
|
frontWithoutFocus.addEventListener('click', () => {
|
|
if (window.ssf) {
|
|
window.ssf.bringToFront(win.name, 'notification');
|
|
} else {
|
|
postMessage(apiCmds.bringToFront, { windowName: win.name, reason: 'notification' });
|
|
}
|
|
});
|
|
|
|
var getVersionInfo = document.getElementById('get-version');
|
|
getVersionInfo.addEventListener('click', () => {
|
|
if (window.ssf) {
|
|
ssf.getVersionInfo().then((verInfo) => {
|
|
let apiVersionInfo = document.getElementById('api-version');
|
|
let containerIdentifier = document.getElementById('container-identifier');
|
|
let version = document.getElementById('container-ver');
|
|
let buildNumber = document.getElementById('build-number');
|
|
let searchApiVer = document.getElementById('search-api-ver');
|
|
|
|
apiVersionInfo.innerText = verInfo.apiVer;
|
|
containerIdentifier.innerText = verInfo.containerIdentifier;
|
|
version.innerText = verInfo.containerVer;
|
|
buildNumber.innerText = verInfo.buildNumber;
|
|
searchApiVer.innerText = verInfo.searchApiVer;
|
|
});
|
|
} else {
|
|
postRequest(apiCmds.getVersionInfo, null, {
|
|
successCallback: (verInfo) => {
|
|
let apiVersionInfo = document.getElementById('api-version');
|
|
let containerIdentifier = document.getElementById('container-identifier');
|
|
let version = document.getElementById('container-ver');
|
|
let buildNumber = document.getElementById('build-number');
|
|
let searchApiVer = document.getElementById('search-api-ver');
|
|
|
|
apiVersionInfo.innerText = verInfo.apiVer;
|
|
containerIdentifier.innerText = verInfo.containerIdentifier;
|
|
version.innerText = verInfo.containerVer;
|
|
buildNumber.innerText = verInfo.buildNumber;
|
|
searchApiVer.innerText = verInfo.searchApiVer;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Core post message api handler
|
|
*/
|
|
const pending = [];
|
|
/**
|
|
* Delete the request once we get the response
|
|
* @returns {boolean}
|
|
* @param id
|
|
*/
|
|
const forgetRequest = (id) => {
|
|
return delete pending[ id ];
|
|
};
|
|
|
|
const broadcastMessage = (method, data) => {
|
|
window.postMessage({ method: method, data: data }, window.origin);
|
|
};
|
|
/**
|
|
*
|
|
* @param method
|
|
* @param data
|
|
* @param handlers
|
|
*/
|
|
const postRequest = (method, data = {}, handlers) => {
|
|
const request = Object.assign({ requestId: ++requestId }, data);
|
|
pending[ request.requestId ] = {
|
|
errorCallback: (error) => {
|
|
return handlers.errorCallback(error)
|
|
&& forgetRequest(request.requestId);
|
|
},
|
|
successCallback: (response) => {
|
|
return handlers.successCallback(response)
|
|
&& forgetRequest(request.requestId);
|
|
},
|
|
};
|
|
broadcastMessage(method, request);
|
|
return request.requestId;
|
|
};
|
|
|
|
const handleResponse = (data) => {
|
|
if (data && data.requestId) {
|
|
const id = data.requestId;
|
|
const content = data;
|
|
const resolver = pending[ id ];
|
|
if (!resolver) {
|
|
return;
|
|
}
|
|
if (content.error) {
|
|
resolver.errorCallback(content.error);
|
|
return;
|
|
}
|
|
if (content.response) {
|
|
resolver.successCallback(content.response);
|
|
return;
|
|
}
|
|
resolver.successCallback(content);
|
|
}
|
|
};
|
|
|
|
const postMessage = (method, data) => {
|
|
window.postMessage({ method, data }, '*');
|
|
};
|
|
|
|
window.addEventListener('message', (event) => {
|
|
const { data, method } = event.data;
|
|
switch (method) {
|
|
case 'activity-callback':
|
|
activityCallback(data);
|
|
break;
|
|
case 'screen-snippet-callback':
|
|
if (data) {
|
|
if (data.type && data.type === 'ERROR') {
|
|
// called when some error occurs during capture
|
|
alert('error getting snippet' + data.message);
|
|
} else if (data.data && data.type === 'image/png;base64') {
|
|
const dataUrl = 'data:' + data.type + ',' + data.data;
|
|
const img = document.getElementById('snippet-img');
|
|
img.src = dataUrl;
|
|
}
|
|
}
|
|
break;
|
|
case 'media-source-callback':
|
|
case 'screen-sharing-indicator-callback':
|
|
case 'get-version-info-callback':
|
|
handleResponse(data);
|
|
console.log(event.data);
|
|
break;
|
|
default:
|
|
console.log(event.data);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Bound Changes
|
|
*/
|
|
// register callback to be notified when size/position changes for win.
|
|
if (window.ssf) {
|
|
ssf.registerBoundsChange(onBoundsChange);
|
|
} else {
|
|
postMessage(apiCmds.registerBoundsChange);
|
|
}
|
|
|
|
function onBoundsChange(arg) {
|
|
console.log('bounds changed for=', arg)
|
|
}
|
|
|
|
/**
|
|
* Protocol handler
|
|
*/
|
|
if (window.ssf) {
|
|
window.ssf.registerProtocolHandler();
|
|
} else {
|
|
postMessage(apiCmds.registerProtocolHandler);
|
|
}
|
|
|
|
/**
|
|
* Activity Detection
|
|
*/
|
|
const activityDetection = document.getElementById('activity-detection');
|
|
const activityStatus = document.getElementById('activity-status');
|
|
activityDetection.addEventListener('click', () => {
|
|
if (window.ssf) {
|
|
window.ssf.registerActivityDetection(5000, activityCallback);
|
|
startActivityInterval();
|
|
} else {
|
|
postMessage(apiCmds.registerActivityDetection, 5000);
|
|
startActivityInterval();
|
|
}
|
|
});
|
|
|
|
let activityTimer;
|
|
const startActivityInterval = () => {
|
|
return setInterval(() => {
|
|
activityStatus.classList.remove('green-dot');
|
|
activityStatus.classList.add('yellow-dot');
|
|
}, 10000);
|
|
};
|
|
const activityCallback = (data) => {
|
|
activityStatus.classList.remove('yellow-dot');
|
|
activityStatus.classList.add('green-dot');
|
|
console.log(data);
|
|
if (activityTimer) {
|
|
clearInterval(activityTimer);
|
|
activityTimer = null;
|
|
}
|
|
activityTimer = startActivityInterval();
|
|
};
|
|
|
|
/**
|
|
* Desktop capture
|
|
*/
|
|
const getSources = document.getElementById('get-sources');
|
|
getSources.addEventListener('click', () => {
|
|
if (window.ssf) {
|
|
ssf.getMediaSource({types: ['window', 'screen']}, function(error, source) {
|
|
if (error) throw error;
|
|
navigator.webkitGetUserMedia({
|
|
audio: false,
|
|
video: {
|
|
mandatory: {
|
|
chromeMediaSource: 'desktop',
|
|
chromeMediaSourceId: source.id,
|
|
minWidth: 1280,
|
|
maxWidth: 1280,
|
|
minHeight: 720,
|
|
maxHeight: 720
|
|
}
|
|
}
|
|
}, stream => {
|
|
handleStream(stream, source.display_id);
|
|
}, handleError);
|
|
});
|
|
} else {
|
|
const successHandler = (data) => {
|
|
const constraints = {
|
|
mandatory: {
|
|
chromeMediaSource: 'desktop',
|
|
maxWidth: screen.width > 1920 ? 1920 : screen.width,
|
|
maxHeight: screen.height > 1080 ? 1080 : screen.height,
|
|
chromeMediaSourceId: data.source.id
|
|
},
|
|
optional: []
|
|
};
|
|
navigator.mediaDevices.getUserMedia({ video: constraints }).then((stream) => {
|
|
handleStream(stream, data.source.display_id);
|
|
});
|
|
};
|
|
const errorHandler = (data) => {
|
|
if (data.error) {
|
|
if (data.error.message === 'User Cancelled') {
|
|
console.error('user canceled');
|
|
} else {
|
|
throw new Error(data.error);
|
|
}
|
|
}
|
|
};
|
|
postRequest(apiCmds.getMediaSource, { types: ['window', 'screen'] }, {
|
|
successCallback: (data) => successHandler(data),
|
|
errorCallback: (error) => errorHandler(error),
|
|
});
|
|
}
|
|
});
|
|
|
|
const handleStream = (stream, displayId) => {
|
|
document.getElementById('video').srcObject = stream;
|
|
if (window.ssf) {
|
|
ssf.showScreenSharingIndicator({
|
|
stream,
|
|
displayId
|
|
}, (event) => {
|
|
console.log('screen-sharing-indicator callback', event);
|
|
if (event.type === 'stopRequested') {
|
|
stream.getVideoTracks().forEach(t => t.stop());
|
|
document.getElementById('video').srcObject = null;
|
|
}
|
|
});
|
|
} else {
|
|
const success = (data) => {
|
|
if (data.error) {
|
|
if (data.error.message === 'User Cancelled') {
|
|
console.error('user canceled');
|
|
} else {
|
|
throw new Error(data.error);
|
|
}
|
|
return;
|
|
}
|
|
if (!data || typeof data.type !== 'string' || !requestId) {
|
|
console.error(`screen-sharing-indicator-callback invalid args ${data}`);
|
|
} else {
|
|
console.log(`screen sharing will be stopped`);
|
|
}
|
|
};
|
|
postRequest(apiCmds.openScreenSharingIndicator, { streamId: stream.id, displayId }, {
|
|
successCallback: (data) => success(data),
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleError = (e) => {
|
|
console.error(e);
|
|
};
|
|
|
|
/**
|
|
* Locale api handler
|
|
*/
|
|
document.getElementById('changeLocale').addEventListener('click', () => {
|
|
const locale = document.getElementById('locale-select').value;
|
|
if (window.ssf) {
|
|
window.ssf.setLocale(locale);
|
|
document.location.reload();
|
|
} else {
|
|
postMessage(apiCmds.setLocale, locale);
|
|
document.location.reload();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Download Manager api handler
|
|
*/
|
|
const download = (filename, text) => {
|
|
const element = document.createElement('a');
|
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
|
element.setAttribute('download', filename);
|
|
|
|
element.style.display = 'none';
|
|
document.body.appendChild(element);
|
|
|
|
element.click();
|
|
|
|
document.body.removeChild(element);
|
|
};
|
|
|
|
// Start file download.
|
|
document.getElementById('download-file1').addEventListener('click', () => {
|
|
const filename = "hello.txt";
|
|
const text = document.getElementById("text-val").value;
|
|
download(filename, text);
|
|
}, false);
|
|
|
|
document.getElementById('download-file2').addEventListener('click', () => {
|
|
const filename = "bye.txt";
|
|
const text = document.getElementById("text-val").value;
|
|
download(filename, text);
|
|
}, false);
|
|
|
|
</script>
|
|
</html>
|