1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-07 19:59:14 -04:00

feat(Clipboard): Clipboard Editor PR Revived (#2492)

* feat(clipboard): Add editing capability to clipboard entries
* Add split save menu for clipboard editor
* Add clipboard editor shortcuts and hints
* Show full clipboard text in editor
* feat(Clipboard): Revive ClipboardEditor PR

- Original PR #1916 by @nabaco
* fix(clipboard): restore Save button targets in editor

---------

Co-authored-by: Nachum Barcohen <38861757+nabaco@users.noreply.github.com>
This commit is contained in:
purian23
2026-05-25 23:25:57 -04:00
committed by GitHub
parent 078180fe42
commit 045ac59a44
7 changed files with 714 additions and 7 deletions
@@ -145,6 +145,7 @@ Item {
onDeleteRequested: clipboardContent.modal.deleteEntry(modelData) onDeleteRequested: clipboardContent.modal.deleteEntry(modelData)
onPinRequested: clipboardContent.modal.pinEntry(modelData) onPinRequested: clipboardContent.modal.pinEntry(modelData)
onUnpinRequested: clipboardContent.modal.unpinEntry(modelData) onUnpinRequested: clipboardContent.modal.unpinEntry(modelData)
onEditRequested: clipboardContent.modal.editEntry(modelData)
} }
} }
@@ -204,6 +205,7 @@ Item {
onDeleteRequested: clipboardContent.modal.deletePinnedEntry(modelData) onDeleteRequested: clipboardContent.modal.deletePinnedEntry(modelData)
onPinRequested: clipboardContent.modal.pinEntry(modelData) onPinRequested: clipboardContent.modal.pinEntry(modelData)
onUnpinRequested: clipboardContent.modal.unpinEntry(modelData) onUnpinRequested: clipboardContent.modal.unpinEntry(modelData)
onEditRequested: clipboardContent.modal.editEntry(modelData)
} }
} }
@@ -0,0 +1,519 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: root
required property var modal
property var keyController: null
property var entry: null
property string editorText: ""
function decodeEntryData(data) {
if (!data) {
return "";
}
if (typeof data !== "string") {
return String(data);
}
const sanitized = data.replace(/\s+/g, "");
if (sanitized.length === 0) {
return "";
}
try {
const chars = new Array(sanitized.length);
for (let i = 0; i < sanitized.length; i++) {
chars[i] = sanitized.charAt(i);
}
let buffer = null;
if (typeof Qt !== "undefined" && typeof Qt.atob === "function") {
buffer = Qt.atob(chars);
} else if (typeof atob === "function") {
const binary = atob(sanitized);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
buffer = bytes.buffer;
}
if (!buffer || buffer.byteLength === 0) {
return data;
}
const bytes = new Uint8Array(buffer);
let binary = "";
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
try {
return decodeURIComponent(escape(binary));
} catch (e) {
return binary;
}
} catch (e) {
return data;
}
}
function setEntry(newEntry) {
entry = newEntry;
editorText = newEntry?.text ?? newEntry?.preview ?? "";
if (editField) {
editField.text = editorText;
}
Qt.callLater(function () {
if (editField) {
editField.forceActiveFocus();
}
});
if (!newEntry || newEntry.isImage) {
return;
}
const requestedId = newEntry.id;
DMSService.sendRequest("clipboard.getEntry", {
"id": requestedId
}, function (response) {
if (response.error) {
return;
}
if (!root.entry || root.entry.id !== requestedId) {
return;
}
const result = response.result;
let fullText = "";
if (result?.data) {
fullText = root.decodeEntryData(result.data);
} else {
fullText = result?.preview ?? "";
}
if (!fullText || fullText.length === 0) {
return;
}
root.editorText = fullText;
if (editField) {
editField.text = fullText;
}
});
}
function saveEntry(action) {
const saveAction = action ?? "history";
DMSService.sendRequest("clipboard.copy", {
"text": root.editorText
}, function (response) {
if (response.error) {
ToastService.showError(I18n.tr("Failed to update clipboard"));
return;
}
if (saveAction === "history") {
modal.mode = "history";
Qt.callLater(function () {
ClipboardService.reset();
ClipboardService.refresh();
if (keyController) {
keyController.reset();
}
});
return;
}
if (saveAction === "close") {
modal.hide();
return;
}
if (saveAction === "paste") {
ClipboardService.pasteClipboard(modal.hide);
}
});
}
function positionSaveMenu() {
saveMenu.width = Math.max(saveMenuColumn.implicitWidth + saveMenu.padding * 2, saveButton.width);
const pos = saveButton.mapToItem(Overlay.overlay, 0, 0);
const popupW = saveMenu.width;
const popupH = saveMenu.height;
const overlayW = Overlay.overlay.width;
const overlayH = Overlay.overlay.height;
let x = pos.x + (saveButton.width - popupW) / 2;
let y = pos.y + saveButton.height + 4;
if (y + popupH > overlayH) {
y = pos.y - popupH - 4;
}
x = Math.max(8, Math.min(x, overlayW - popupW - 8));
y = Math.max(8, y);
saveMenu.x = x;
saveMenu.y = y;
}
function toggleSaveMenu() {
if (saveMenu.visible) {
saveMenu.close();
return;
}
saveMenu.open();
positionSaveMenu();
Qt.callLater(positionSaveMenu);
}
Shortcut {
sequences: ["Escape"]
enabled: modal.mode === "editor"
onActivated: modal.mode = "history"
}
Column {
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingM
Item {
id: editorHeader
width: parent.width
height: ClipboardConstants.headerHeight
DankActionButton {
iconName: "arrow_back"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
onClicked: modal.mode = "history"
}
StyledText {
text: I18n.tr("Edit Clipboard")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
onClicked: modal.mode = "history"
}
}
StyledRect {
id: editFieldContainer
width: parent.width
height: Math.max(Theme.fontSizeMedium * 8, parent.height - editorHeader.height - editorActions.height - Theme.spacingM * 2)
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: editField.activeFocus ? Theme.primary : Theme.outlineMedium
border.width: editField.activeFocus ? 2 : 1
clip: true
DankIcon {
id: editIcon
name: "edit"
size: Theme.iconSize
color: editField.activeFocus ? Theme.primary : Theme.surfaceVariantText
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.top: parent.top
anchors.topMargin: Theme.spacingM
}
DankFlickable {
id: editScroll
anchors.left: editIcon.right
anchors.leftMargin: Theme.spacingS
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS
clip: true
contentWidth: width
contentHeight: editField.height
TextEdit {
id: editField
width: editScroll.width
height: Math.max(editScroll.height, contentHeight)
text: root.editorText
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
wrapMode: TextEdit.Wrap
selectByMouse: true
onTextChanged: root.editorText = text
Keys.onPressed: function (event) {
const hasCtrl = (event.modifiers & Qt.ControlModifier) !== 0;
const hasShift = (event.modifiers & Qt.ShiftModifier) !== 0;
if (hasCtrl && event.key === Qt.Key_S) {
root.saveEntry(hasShift ? "close" : "history");
event.accepted = true;
return;
}
if (hasCtrl && hasShift && event.key === Qt.Key_V) {
root.saveEntry("paste");
event.accepted = true;
return;
}
}
}
}
StyledText {
text: I18n.tr("Edit clipboard text")
font.pixelSize: Theme.fontSizeMedium
color: Theme.outlineButton
anchors.left: editScroll.left
anchors.right: editScroll.right
anchors.top: editScroll.top
anchors.bottom: editScroll.bottom
visible: editField.text.length === 0 && !editField.activeFocus
wrapMode: Text.WordWrap
}
}
Row {
id: editorActions
width: parent.width
spacing: Theme.spacingS
Item {
id: buttonSpacer
width: Math.max(0, parent.width - cancelButton.width - saveButton.width - Theme.spacingS)
height: 1
}
DankButton {
id: cancelButton
text: I18n.tr("Cancel")
backgroundColor: Theme.surfaceContainerHigh
textColor: Theme.surfaceText
onClicked: modal.mode = "history"
}
Item {
id: saveButton
readonly property int buttonHeight: cancelButton.buttonHeight
readonly property int arrowWidth: Theme.iconSizeLarge
width: cancelButton.width
height: buttonHeight
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: Theme.primary
}
Item {
id: saveMainArea
anchors.left: parent.left
anchors.right: saveArrowArea.left
anchors.top: parent.top
anchors.bottom: parent.bottom
}
StyledText {
text: I18n.tr("Save")
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.onPrimary
anchors.centerIn: saveMainArea
}
Item {
id: saveArrowArea
width: saveButton.arrowWidth
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
}
Rectangle {
width: 1
height: parent.height - cancelButton.horizontalPadding
color: Theme.withAlpha(Theme.onPrimary, 0.2)
anchors.right: saveArrowArea.left
anchors.verticalCenter: parent.verticalCenter
}
DankIcon {
name: saveMenu.visible ? "expand_less" : "expand_more"
size: Theme.iconSizeSmall
color: Theme.onPrimary
anchors.centerIn: saveArrowArea
}
StateLayer {
z: 1
anchors.fill: saveMainArea
stateColor: Theme.onPrimary
onClicked: root.saveEntry("history")
}
StateLayer {
z: 1
anchors.fill: saveArrowArea
stateColor: Theme.onPrimary
onClicked: root.toggleSaveMenu()
}
}
}
Popup {
id: saveMenu
parent: Overlay.overlay
padding: Theme.spacingM
modal: true
dim: false
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
background: StyledRect {
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.outlineMedium
border.width: 1
}
contentItem: Column {
id: saveMenuColumn
spacing: Theme.spacingXS
StyledRect {
implicitWidth: saveMenuRow.implicitWidth + Theme.spacingS * 2
implicitHeight: saveMenuRow.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: saveMenuSaveArea.containsMouse ? Theme.surfaceVariant : "transparent"
Row {
id: saveMenuRow
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "save"
size: Theme.iconSizeSmall
color: Theme.surfaceText
}
StyledText {
text: I18n.tr("Save")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
}
}
MouseArea {
id: saveMenuSaveArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
saveMenu.close();
root.saveEntry("history");
}
}
}
StyledRect {
implicitWidth: saveMenuCloseRow.implicitWidth + Theme.spacingS * 2
implicitHeight: saveMenuCloseRow.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: saveMenuCloseArea.containsMouse ? Theme.surfaceVariant : "transparent"
Row {
id: saveMenuCloseRow
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "close"
size: Theme.iconSizeSmall
color: Theme.surfaceText
}
StyledText {
text: I18n.tr("Save and close")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
}
}
MouseArea {
id: saveMenuCloseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
saveMenu.close();
root.saveEntry("close");
}
}
}
StyledRect {
implicitWidth: saveMenuPasteRow.implicitWidth + Theme.spacingS * 2
implicitHeight: saveMenuPasteRow.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: saveMenuPasteArea.containsMouse ? Theme.surfaceVariant : "transparent"
opacity: modal.wtypeAvailable ? 1 : 0.5
Row {
id: saveMenuPasteRow
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "content_paste"
size: Theme.iconSizeSmall
color: Theme.surfaceText
}
StyledText {
text: I18n.tr("Save and paste")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
}
}
MouseArea {
id: saveMenuPasteArea
anchors.fill: parent
hoverEnabled: true
enabled: modal.wtypeAvailable
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
saveMenu.close();
root.saveEntry("paste");
}
}
}
}
}
}
}
+20 -2
View File
@@ -17,6 +17,7 @@ Rectangle {
signal deleteRequested signal deleteRequested
signal pinRequested signal pinRequested
signal unpinRequested signal unpinRequested
signal editRequested
readonly property string entryType: modal ? modal.getEntryType(entry) : "text" readonly property string entryType: modal ? modal.getEntryType(entry) : "text"
readonly property string entryPreview: modal ? modal.getEntryPreview(entry) : "" readonly property string entryPreview: modal ? modal.getEntryPreview(entry) : ""
@@ -70,6 +71,20 @@ Rectangle {
onClicked: entry.pinned ? unpinRequested() : pinRequested() onClicked: entry.pinned ? unpinRequested() : pinRequested()
} }
DankActionButton {
iconName: "edit"
iconSize: Theme.iconSize - 6
iconColor: Theme.surfaceText
onClicked: {
if (entryType === "image") {
// TODO - forward to editing software
} else {
editRequested();
}
}
}
DankActionButton { DankActionButton {
iconName: "close" iconName: "close"
iconSize: Theme.iconSize - 6 iconSize: Theme.iconSize - 6
@@ -142,8 +157,11 @@ Rectangle {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.left: parent.left
anchors.rightMargin: 80 anchors.right: actionButtons.left
anchors.rightMargin: Theme.spacingS
anchors.top: parent.top
anchors.bottom: parent.bottom
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: mouse => { onPressed: mouse => {
@@ -43,6 +43,18 @@ DankModal {
service: ClipboardService service: ClipboardService
} }
property string mode: "history"
onModeChanged: {
if (mode !== "history") {
return;
}
Qt.callLater(function () {
if (contentLoader.item?.searchField) {
contentLoader.item.searchField.forceActiveFocus();
}
});
}
function updateFilteredModel() { function updateFilteredModel() {
ClipboardService.updateFilteredModel(); ClipboardService.updateFilteredModel();
} }
@@ -61,6 +73,7 @@ DankModal {
function show() { function show() {
open(); open();
mode = "history";
activeImageLoads = 0; activeImageLoads = 0;
shouldHaveFocus = true; shouldHaveFocus = true;
ClipboardService.reset(); ClipboardService.reset();
@@ -130,6 +143,21 @@ DankModal {
return ClipboardService.getEntryType(entry); return ClipboardService.getEntryType(entry);
} }
function editEntry(entry) {
if (!entry) {
return;
}
if (entry.isImage) {
return;
}
const editor = contentLoader.item?.editorView;
if (!editor) {
return;
}
editor.setEntry(entry);
mode = "editor";
}
visible: false visible: false
modalWidth: ClipboardConstants.modalWidth modalWidth: ClipboardConstants.modalWidth
modalHeight: ClipboardConstants.modalHeight modalHeight: ClipboardConstants.modalHeight
@@ -138,6 +166,7 @@ DankModal {
borderColor: Theme.outlineMedium borderColor: Theme.outlineMedium
borderWidth: 1 borderWidth: 1
enableShadow: true enableShadow: true
closeOnEscapeKey: mode !== "editor"
onBackgroundClicked: hide() onBackgroundClicked: hide()
modalFocusScope.Keys.onPressed: function (event) { modalFocusScope.Keys.onPressed: function (event) {
keyboardController.handleKey(event); keyboardController.handleKey(event);
@@ -174,9 +203,109 @@ DankModal {
property var confirmDialog: clearConfirmDialog property var confirmDialog: clearConfirmDialog
clipboardContent: Component { clipboardContent: Component {
ClipboardContent { Item {
modal: clipboardHistoryModal id: viewContainer
clearConfirmDialog: clipboardHistoryModal.confirmDialog
property alias editorView: editorView
property alias searchField: historyContent.searchField
anchors.fill: parent
Item {
id: historyView
anchors.fill: parent
opacity: 1
scale: 1
visible: opacity > 0.01
enabled: clipboardHistoryModal.mode === "history"
ClipboardContent {
id: historyContent
anchors.fill: parent
modal: clipboardHistoryModal
clearConfirmDialog: clipboardHistoryModal.confirmDialog
}
}
ClipboardEditor {
id: editorView
anchors.fill: parent
opacity: 0
scale: 0.98
visible: opacity > 0.01
enabled: clipboardHistoryModal.mode === "editor"
focus: clipboardHistoryModal.mode === "editor"
modal: clipboardHistoryModal
keyController: keyboardController
}
states: [
State {
name: "history"
when: clipboardHistoryModal.mode === "history"
PropertyChanges {
target: historyView
opacity: 1
scale: 1
}
PropertyChanges {
target: editorView
opacity: 0
scale: 0.98
}
},
State {
name: "editor"
when: clipboardHistoryModal.mode === "editor"
PropertyChanges {
target: historyView
opacity: 0
scale: 0.98
}
PropertyChanges {
target: editorView
opacity: 1
scale: 1
}
}
]
transitions: [
Transition {
from: "history"
to: "editor"
ParallelAnimation {
NumberAnimation {
property: "opacity"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
NumberAnimation {
property: "scale"
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
},
Transition {
from: "editor"
to: "history"
ParallelAnimation {
NumberAnimation {
property: "opacity"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
NumberAnimation {
property: "scale"
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
}
]
} }
} }
} }
@@ -66,7 +66,24 @@ QtObject {
} }
} }
function editSelected() {
const entries = modal.activeTab === "saved" ? ClipboardService.pinnedEntries : ClipboardService.unpinnedEntries;
if (!entries || entries.length === 0) {
return;
}
const index = ClipboardService.selectedIndex >= 0 && ClipboardService.selectedIndex < entries.length ? ClipboardService.selectedIndex : 0;
modal.editEntry(entries[index]);
}
function handleKey(event) { function handleKey(event) {
if (modal.mode === "editor") {
if (event.key === Qt.Key_Escape) {
modal.mode = "history";
event.accepted = true;
}
return;
}
switch (event.key) { switch (event.key) {
case Qt.Key_Escape: case Qt.Key_Escape:
if (ClipboardService.keyboardNavigationActive) { if (ClipboardService.keyboardNavigationActive) {
@@ -152,6 +169,10 @@ QtObject {
event.accepted = true; event.accepted = true;
} }
return; return;
case Qt.Key_E:
editSelected();
event.accepted = true;
return;
} }
} }
@@ -10,7 +10,7 @@ Rectangle {
readonly property string hintsText: { readonly property string hintsText: {
if (!wtypeAvailable) if (!wtypeAvailable)
return I18n.tr("Ctrl+Tab: Switch Tab • Ctrl+S: Pin/Unpin • Shift+Del: Clear All • Esc: Close"); return I18n.tr("Ctrl+Tab: Switch Tab • Ctrl+S: Pin/Unpin • Shift+Del: Clear All • Esc: Close");
return enterToPaste ? I18n.tr("Ctrl+Tab: Switch Tab • Ctrl+S: Pin/Unpin • Shift+Enter: Copy • Shift+Del: Clear All • Esc: Close", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("Ctrl+Tab: Switch Tab • Ctrl+S: Pin/Unpin • Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close"); return enterToPaste ? I18n.tr("Ctrl+Tab: Switch Tabs • Ctrl+S: Pin/Unpin • Shift+Enter: Copy • Shift+Del: Clear All • F10: Help • Esc: Close", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("Ctrl+Tab: Switch Tabs • Ctrl+S: Pin/Unpin • Shift+Enter: Paste • Shift+Del: Clear All • F10: Help • Esc: Close");
} }
height: ClipboardConstants.keyboardHintsHeight height: ClipboardConstants.keyboardHintsHeight
@@ -22,13 +22,17 @@ Rectangle {
z: 100 z: 100
Column { Column {
width: parent.width - Theme.spacingL * 2
anchors.centerIn: parent anchors.centerIn: parent
spacing: 2 spacing: 2
StyledText { StyledText {
text: keyboardHints.enterToPaste ? I18n.tr("↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help") text: keyboardHints.enterToPaste ? I18n.tr("↑/↓: Navigate • Enter: Paste • Ctrl+C: Copy • Del: Delete • Ctrl+E: Edit • Ctrl+S: Pin/Unpin • F10: Help", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • Ctrl+E: Edit • Ctrl+S: Pin/Unpin • F10: Help")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
width: parent.width
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -36,6 +40,9 @@ Rectangle {
text: keyboardHints.hintsText text: keyboardHints.hintsText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
width: parent.width
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
} }
+11
View File
@@ -240,6 +240,17 @@ Singleton {
}); });
} }
function pasteClipboard(closeCallback) {
if (!wtypeAvailable) {
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
return;
}
if (closeCallback) {
closeCallback();
}
pasteTimer.start();
}
function pasteEntry(entry, closeCallback) { function pasteEntry(entry, closeCallback) {
if (!wtypeAvailable) { if (!wtypeAvailable) {
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support")); ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));