@eclipse-scout/core
Version:
Eclipse Scout runtime
151 lines (137 loc) • 5.15 kB
text/typescript
/*
* Copyright (c) 2010, 2025 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
import {DesktopNotification, FocusRule, scout, Session, Status, Widget} from '../index';
import $ from 'jquery';
export interface ClipboardTextCopyOptions {
/**
* The text to write to the clipboard.
*/
text: string;
/**
* Widget that wants to copy the text. Recommended.
* Used to retrieve the session and the document.
*/
parent?: Widget;
/**
* Scout session object, used to resolve texts and access the focus manager. Only required when "parent" is not set.
*/
session?: Session;
/**
* If true, a desktop notification is shown when copying has been completed. Requires the "parent" option to be present.
* If this is true, the {@link copyText} method returns null. Otherwise, it returns a promise that is resolved or rejected when the copying is complete.
*/
showNotification?: boolean;
}
export const clipboard = {
/**
* Copies the given text to the clipboard. To make this work, the method must be called inside
* a "user action" (i.e. mouse or keyboard event handler). For security reasons, the access to
* the clipboard is blocked by the browser in other contexts (e.g. asynchronous callbacks).
*
* @param options mandatory
* @returns a promise or null if {@link options.showNotification} is true.
*/
copyText(options: ClipboardTextCopyOptions): JQuery.Promise<void> {
scout.assertParameter('options', options);
if (options.parent && !options.session) {
options.session = options.parent.session;
}
scout.assertProperty(options, 'session');
let promise = clipboard._copyText(options);
if (options.parent && scout.nvl(options.showNotification, true)) {
clipboard._showNotification(options, promise);
return null;
}
return promise;
},
/** @internal */
_copyText(options: ClipboardTextCopyOptions): JQuery.Promise<void> {
let deferred = $.Deferred();
// Modern clipboard API
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
let win = options?.parent?.window(true) || window;
if (win.navigator.clipboard) {
win.navigator.clipboard.writeText(options.text)
.then((...args) => deferred.resolve(...args))
.catch((...args) => deferred.reject(...args));
return deferred.promise();
}
// Fallback for browsers that don't support the modern clipboard API (IE, Safari, Chrome < 66, Firefox < 63)
// Create invisible textarea field and use document command "copy" to copy the text to the clipboard
let doc = options?.parent?.document(true) || document;
let f = doc.createElement('textarea');
f.style.position = 'fixed';
f.style.opacity = '0.0';
f.value = options.text;
doc.body.appendChild(f);
// Preserve focus
let $f = $(f);
options.session.focusManager.installFocusContext($f, FocusRule.AUTO);
f.select(); // cannot use jquery select(), because that is overridden by jquery-scout
try {
let successful = doc.execCommand('copy');
if (successful) {
deferred.resolve();
} else {
deferred.reject();
}
} catch (err) {
deferred.reject(err);
} finally {
// Restore focus
options.session.focusManager.uninstallFocusContext($f);
doc.body.removeChild(f);
}
return deferred.promise();
},
/** @internal */
_showNotification(options: ClipboardTextCopyOptions, promise: JQuery.Promise<void>) {
let status = clipboard._successStatus(options.parent.session);
promise
.catch(() => {
status = clipboard._failedStatus(options.parent.session);
})
.then(() => {
clipboard.showNotification(options.parent, status);
});
},
/** @internal */
_successStatus(session: Session): Status {
return new Status({
message: session.text('ui.CopyToClipboardSuccessStatus'),
severity: Status.Severity.INFO
});
},
/** @internal */
_failedStatus(session: Session): Status {
return new Status({
message: session.text('ui.CopyToClipboardFailedStatus'),
severity: Status.Severity.WARNING
});
},
/**
* Shows a short desktop notification. By default, it informs the user that the content
* has been copied to the clipboard successfully. By passing a different status, the
* message can be changed.
*
* @param parent Widget that wants to show the notification. Mandatory. Required for NLS texts.
*/
showNotification(parent: Widget, status?: Status) {
scout.assertParameter('parent', parent);
status = status || clipboard._successStatus(parent.session);
let notification = scout.create(DesktopNotification, {
parent: parent,
closable: false,
duration: status.isValid() ? 1234 : 3456, // use longer duration for errors because error message is longer
status: status
});
notification.show();
}
};