diff --git a/browser/Makefile.am b/browser/Makefile.am
index fe7d3bfa6..20f199dac 100644
--- a/browser/Makefile.am
+++ b/browser/Makefile.am
@@ -314,6 +314,7 @@ COOL_JS_LST =\
src/map/handler/Map.StateChanges.js \
src/map/handler/Map.WOPI.js \
src/layer/marker/Marker.Drag.js \
+ src/control/Control.AboutDialog.ts \
src/control/Control.Toolbar.js \
src/control/Control.Command.js \
src/control/Control.js \
@@ -764,6 +765,7 @@ pot:
admin/src/Util.js \
js/global.js \
src/control/ColorPicker.ts \
+ src/control/Control.AboutDialog.ts \
src/control/Control.AlertDialog.js \
src/control/Control.Command.js \
src/control/Control.ContextMenu.js \
diff --git a/browser/src/control/Control.AboutDialog.ts b/browser/src/control/Control.AboutDialog.ts
new file mode 100644
index 000000000..de674c66e
--- /dev/null
+++ b/browser/src/control/Control.AboutDialog.ts
@@ -0,0 +1,265 @@
+/*
+ * Copyright the Collabora Online contributors.
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+/*
+ * AboutDialog - implements Help - About dialog with version and warnings
+ */
+
+declare var JSDialog: any;
+declare var brandProductName: any;
+declare var brandProductURL: any;
+declare var sanitizeUrl: any;
+
+class AboutDialog {
+ map: any;
+
+ constructor(map: any) {
+ this.map = map;
+ }
+
+ private aboutDialogClickHandler(e: any) {
+ if (e.detail === 3) {
+ this.map._debug.toggle();
+ }
+ }
+
+ public show() {
+ const windowAny = window as any;
+ // Just as a test to exercise the Async Trace Event functionality, uncomment this
+ // line and the asyncTraceEvent.finish() below.
+ // var asyncTraceEvent = app.socket.createAsyncTraceEvent('cool-showLOAboutDialog');
+
+ const aboutDialogId = 'about-dialog';
+ // Move the div sitting in 'body' as content and make it visible
+ const content: HTMLElement = document
+ .getElementById(aboutDialogId)
+ .cloneNode(true) as HTMLElement;
+ content.style.display = 'block';
+
+ // fill product-name and product-string
+ let productName;
+ if (windowAny.ThisIsAMobileApp) {
+ productName = windowAny.MobileAppName;
+ } else {
+ productName =
+ typeof brandProductName !== 'undefined'
+ ? brandProductName
+ : 'Collabora Online Development Edition (unbranded)';
+ }
+ var productURL =
+ typeof brandProductURL !== 'undefined'
+ ? brandProductURL
+ : 'https://collaboraonline.github.io/';
+
+ const productNameElement = content.querySelector(
+ '#product-name',
+ ) as HTMLElement;
+ productNameElement.innerText = productName;
+ content.classList.add(
+ 'product-' +
+ productName
+ .split(/[ ()]+/)
+ .join('-')
+ .toLowerCase(),
+ );
+
+ var productString = _('This version of %productName is powered by');
+ var productNameWithURL;
+ if (!windowAny.ThisIsAMobileApp)
+ productNameWithURL =
+ '' +
+ productName +
+ '';
+ else productNameWithURL = productName;
+
+ const productStringElement = content.querySelector(
+ '#product-string',
+ ) as HTMLElement;
+ if (productStringElement)
+ productStringElement.innerText = productString.replace(
+ '%productName',
+ productNameWithURL,
+ );
+
+ const slowProxyElement = content.querySelector(
+ '#slow-proxy',
+ ) as HTMLElement;
+ if (windowAny.socketProxy) slowProxyElement.innerText = _('"Slow Proxy"');
+
+ const routeTokenElement = content.querySelector(
+ '#routeToken',
+ ) as HTMLElement;
+ if (windowAny.indirectSocket)
+ routeTokenElement.innerText = 'RouteToken: ' + windowAny.routeToken;
+
+ this.map.uiManager.showYesNoButton(
+ aboutDialogId + '-box',
+ productName,
+ '',
+ _('OK'),
+ null,
+ null,
+ null,
+ true,
+ );
+ var box = document.getElementById(aboutDialogId + '-box');
+ var innerDiv = L.DomUtil.create('div', '', null);
+ box.insertBefore(innerDiv, box.firstChild);
+ innerDiv.innerHTML = content.outerHTML;
+
+ var form = document.getElementById('about-dialog-box');
+
+ form.addEventListener('click', this.aboutDialogClickHandler.bind(this));
+ form.addEventListener('keyup', this.aboutDialogKeyHandler.bind(this));
+ form.querySelector('#coolwsd-version').querySelector('a').focus();
+ var copyversion = L.DomUtil.create(
+ 'button',
+ 'ui-pushbutton jsdialog',
+ null,
+ );
+ copyversion.setAttribute('id', 'modal-dialog-about-dialog-box-copybutton');
+ copyversion.setAttribute(
+ 'title',
+ _('Copy all version information in English'),
+ );
+ var img = L.DomUtil.create('img', null, null);
+ L.LOUtil.setImage(img, 'lc_copy.svg', this.map);
+ copyversion.innerHTML =
+ '';
+ copyversion.addEventListener(
+ 'click',
+ this.copyVersionInfoToClipboard.bind(this),
+ );
+ this.map.uiManager.enableTooltip(copyversion);
+ var aboutok = document.getElementById(
+ 'modal-dialog-about-dialog-box-yesbutton',
+ );
+ if (aboutok) {
+ aboutok.before(copyversion);
+ }
+ }
+
+ private aboutDialogKeyHandler(e: KeyboardEvent) {
+ if (e.key === 'd') {
+ this.map._debug.toggle();
+ } else if (e.key === 'l') {
+ // L toggges the Online logging level between the default (whatever
+ // is set in coolwsd.xml or on the coolwsd command line) and the
+ // most verbose a client is allowed to set (which also can be set in
+ // coolwsd.xml or on the coolwsd command line).
+ //
+ // In a typical developer "make run" setup, the default is "trace"
+ // so there is nothing more verbose. But presumably it is different
+ // in production setups.
+
+ app.socket.threadLocalLoggingLevelToggle =
+ !app.socket.threadLocalLoggingLevelToggle;
+
+ const newLogLevel = app.socket.threadLocalLoggingLevelToggle
+ ? 'verbose'
+ : 'default';
+
+ app.socket.sendMessage('loggingleveloverride ' + newLogLevel);
+
+ let logLevelInformation;
+ if (newLogLevel === 'default')
+ logLevelInformation = 'default (from coolwsd.xml)';
+ else if (newLogLevel === 'verbose')
+ logLevelInformation = 'most verbose (from coolwsd.xml)';
+ else if (newLogLevel === 'terse')
+ logLevelInformation = 'least verbose (from coolwsd.xml)';
+ else logLevelInformation = newLogLevel;
+
+ console.debug('Log level: ' + logLevelInformation);
+ }
+ }
+
+ private copyVersionInfoToClipboard() {
+ let text =
+ 'COOLWSD version: ' +
+ this.getVersionInfoFromClass('coolwsd-version') +
+ '\n';
+ text +=
+ 'LOKit version: ' + this.getVersionInfoFromClass('lokit-version') + '\n';
+ text += 'Served by: ' + document.getElementById('os-info').innerText + '\n';
+ text +=
+ 'Server ID: ' + document.getElementById('coolwsd-id').innerText + '\n';
+ text = text.replace(/\u00A0/g, ' ');
+
+ if (navigator.clipboard && window.isSecureContext) {
+ navigator.clipboard
+ .writeText(text)
+ .then(
+ function () {
+ window.console.log('Text copied to clipboard');
+ this.contentHasBeenCopiedShowSnackbar();
+ }.bind(this),
+ )
+ .catch(function (error) {
+ window.console.error('Error copying text to clipboard:', error);
+ });
+ } else {
+ var textArea = document.createElement('textarea');
+ textArea.style.position = 'absolute';
+ textArea.style.opacity = '0';
+ textArea.value = text;
+ document.body.appendChild(textArea);
+ textArea.select();
+ try {
+ document.execCommand('copy');
+ window.console.log('Text copied to clipboard');
+ this.contentHasBeenCopiedShowSnackbar();
+ } catch (error) {
+ window.console.error('Error copying text to clipboard:', error);
+ } finally {
+ document.body.removeChild(textArea);
+ }
+ }
+ }
+
+ private contentHasBeenCopiedShowSnackbar() {
+ const timeout = 1000;
+ this.map.uiManager.showSnackbar(
+ 'Version information has been copied',
+ null,
+ null,
+ timeout,
+ );
+ const copybutton = document.querySelector(
+ '#modal-dialog-about-dialog-box-copybutton > img',
+ );
+ L.LOUtil.setImage(copybutton, 'lc_clipboard-check.svg', this.map);
+ setTimeout(() => {
+ L.LOUtil.setImage(copybutton, 'lc_copy.svg', this.map);
+ }, timeout);
+ }
+
+ private getVersionInfoFromClass(className: string) {
+ const versionElement = document.getElementById(className);
+ let versionInfo = versionElement.innerText;
+
+ const gitHashIndex = versionInfo.indexOf('git hash');
+ if (gitHashIndex > -1) {
+ versionInfo =
+ versionInfo.slice(0, gitHashIndex) +
+ '(' +
+ versionInfo.slice(gitHashIndex) +
+ ')';
+ }
+
+ return versionInfo;
+ }
+}
+
+// Initiate the class.
+JSDialog.aboutDialog = (map: any) => {
+ return new AboutDialog(map);
+};
diff --git a/browser/src/control/Control.UIManager.js b/browser/src/control/Control.UIManager.js
index 0f041c6be..771534740 100644
--- a/browser/src/control/Control.UIManager.js
+++ b/browser/src/control/Control.UIManager.js
@@ -236,6 +236,7 @@ L.Control.UIManager = L.Control.extend({
this.map.addControl(L.control.contextMenu());
this.map.userList = L.control.userList();
this.map.addControl(this.map.userList);
+ this.map.aboutDialog = JSDialog.aboutDialog(this.map);
var openBusyPopup = function(label) {
this.busyPopupTimer = setTimeout(function() {
diff --git a/browser/src/control/Toolbar.js b/browser/src/control/Toolbar.js
index c09cb68f5..80ea32255 100644
--- a/browser/src/control/Toolbar.js
+++ b/browser/src/control/Toolbar.js
@@ -12,7 +12,7 @@
* Toolbar handler
*/
-/* global app $ window sanitizeUrl brandProductName brandProductURL _ */
+/* global app $ window brandProductName _ */
L.Map.include({
// a mapping of uno commands to more readable toolbar items
@@ -724,165 +724,8 @@ L.Map.include({
});
},
- aboutDialogKeyHandler: function(event) {
- if (event.key === 'd') {
- this._debug.toggle();
- } else if (event.key === 'l') {
- // L toggges the Online logging level between the default (whatever
- // is set in coolwsd.xml or on the coolwsd command line) and the
- // most verbose a client is allowed to set (which also can be set in
- // coolwsd.xml or on the coolwsd command line).
- //
- // In a typical developer "make run" setup, the default is "trace"
- // so there is nothing more verbose. But presumably it is different
- // in production setups.
-
- app.socket.threadLocalLoggingLevelToggle = !app.socket.threadLocalLoggingLevelToggle;
-
- var newLogLevel = (app.socket.threadLocalLoggingLevelToggle ? 'verbose' : 'default');
-
- app.socket.sendMessage('loggingleveloverride ' + newLogLevel);
-
- var logLevelInformation;
- if (newLogLevel === 'default')
- logLevelInformation = 'default (from coolwsd.xml)';
- else if (newLogLevel === 'verbose')
- logLevelInformation = 'most verbose (from coolwsd.xml)';
- else if (newLogLevel === 'terse')
- logLevelInformation = 'least verbose (from coolwsd.xml)';
- else
- logLevelInformation = newLogLevel;
-
- console.debug('Log level: ' + logLevelInformation);
- }
- },
-
- aboutDialogClickHandler: function(event) {
- if (event.detail === 3) {
- this._debug.toggle();
- }
- },
-
showLOAboutDialog: function() {
- // Just as a test to exercise the Async Trace Event functionality, uncomment this
- // line and the asyncTraceEvent.finish() below.
- // var asyncTraceEvent = app.socket.createAsyncTraceEvent('cool-showLOAboutDialog');
-
- var aboutDialogId = 'about-dialog';
- // Move the div sitting in 'body' as content and make it visible
- var content = document.getElementById(aboutDialogId).cloneNode(true);
- content.style.display = 'block';
-
- // fill product-name and product-string
- var productName;
- if (window.ThisIsAMobileApp) {
- productName = window.MobileAppName;
- } else {
- productName = (typeof brandProductName !== 'undefined') ? brandProductName : 'Collabora Online Development Edition (unbranded)';
- }
- var productURL = (typeof brandProductURL !== 'undefined') ? brandProductURL : 'https://collaboraonline.github.io/';
-
- content.querySelector('#product-name').innerText = productName;
- content.classList.add('product-' + productName.split(/[ ()]+/).join('-').toLowerCase());
-
- var productString = _('This version of %productName is powered by');
- var productNameWithURL;
- if (!window.ThisIsAMobileApp)
- productNameWithURL = '' + productName + '';
- else
- productNameWithURL = productName;
-
- if (content.querySelector('#product-string'))
- content.querySelector('#product-string').innerText = productString.replace('%productName', productNameWithURL);
-
- if (window.socketProxy)
- content.querySelector('#slow-proxy').innerText = _('"Slow Proxy"');
-
- var map = this;
- if (window.indirectSocket)
- content.querySelector('#routeToken').innerText = 'RouteToken: ' + window.routeToken;
-
- map.uiManager.showYesNoButton(aboutDialogId + '-box', productName, '', _('OK'), null, null, null, true);
- var box = document.getElementById(aboutDialogId + '-box');
- var innerDiv = L.DomUtil.create('div', '', null);
- box.insertBefore(innerDiv, box.firstChild);
- innerDiv.innerHTML = content.outerHTML;
-
- var form = document.getElementById('about-dialog-box');
-
- form.addEventListener('click', this.aboutDialogClickHandler.bind(this));
- form.addEventListener('keyup', this.aboutDialogKeyHandler.bind(this));
- form.querySelector('#coolwsd-version').querySelector('a').focus();
- var copyversion = L.DomUtil.create('button', 'ui-pushbutton jsdialog', null);
- copyversion.setAttribute('id', 'modal-dialog-about-dialog-box-copybutton');
- copyversion.setAttribute('title', _('Copy all version information in English'));
- var img = L.DomUtil.create('img', null, null);
- L.LOUtil.setImage(img, 'lc_copy.svg', map);
- copyversion.innerHTML = '';
- copyversion.addEventListener('click', this.copyVersionInfoToClipboard.bind(this));
- map.uiManager.enableTooltip(copyversion);
- var aboutok = document.getElementById('modal-dialog-about-dialog-box-yesbutton');
- if (aboutok) {
- aboutok.before(copyversion);
- }
- },
-
- getVersionInfoFromClass: function(className) {
- var versionElement = document.getElementById(className);
- var versionInfo = versionElement.innerText;
-
- var gitHashIndex = versionInfo.indexOf('git hash');
- if (gitHashIndex > -1) {
- versionInfo = versionInfo.slice(0, gitHashIndex) + '(' + versionInfo.slice(gitHashIndex) + ')';
- }
-
- return versionInfo;
- },
-
- copyVersionInfoToClipboard: function() {
- var text = 'COOLWSD version: ' + this.getVersionInfoFromClass('coolwsd-version') + '\n';
- text += 'LOKit version: ' + this.getVersionInfoFromClass('lokit-version') + '\n';
- text += 'Served by: ' + document.getElementById('os-info').innerText + '\n';
- text += 'Server ID: ' + document.getElementById('coolwsd-id').innerText + '\n';
- text = text.replace(/\u00A0/g, ' ');
-
- if (navigator.clipboard && window.isSecureContext) {
- navigator.clipboard.writeText(text)
- .then(function() {
- window.console.log('Text copied to clipboard');
- this.contentHasBeenCopiedShowSnackbar();
- }.bind(this))
- .catch(function(error) {
- window.console.error('Error copying text to clipboard:', error);
- });
- } else {
- var textArea = document.createElement('textarea');
- textArea.style.position = 'absolute';
- textArea.style.opacity = 0;
- textArea.value = text;
- document.body.appendChild(textArea);
- textArea.select();
- try {
- document.execCommand('copy');
- window.console.log('Text copied to clipboard');
- this.contentHasBeenCopiedShowSnackbar();
- } catch (error) {
- window.console.error('Error copying text to clipboard:', error);
- } finally {
- document.body.removeChild(textArea);
- }
- }
- },
-
- contentHasBeenCopiedShowSnackbar: function() {
- var timeout = 1000;
- this.uiManager.showSnackbar('Version information has been copied', null, null, timeout);
- var copybutton = document.querySelector('#modal-dialog-about-dialog-box-copybutton > img');
- L.LOUtil.setImage(copybutton, 'lc_clipboard-check.svg', this);
- setTimeout(function () {
- L.LOUtil.setImage(copybutton, 'lc_copy.svg', this);
- }.bind(this), timeout);
+ this.aboutDialog.show();
},
extractContent: function(html) {