Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions packages/main/cypress/specs/Tokenizer.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,52 @@ describe("Clipboard Operations", () => {
// Only the selected token should be copied
cy.get("@clipboardWrite").should("have.been.calledOnceWith", "Selected");
});

it("should copy focused token text when no tokens are selected", () => {
cy.mount(
<Tokenizer>
<Token text="Focused"></Token>
<Token text="Other"></Token>
</Tokenizer>
);

// Tab into the tokenizer to focus the first token without selecting it
cy.realPress("Tab");
cy.get("[ui5-token]").eq(0).should("have.prop", "focused", true);
cy.get("[ui5-token]").eq(0).should("have.prop", "selected", false);

cy.window().then((win) => {
cy.stub(win.navigator.clipboard, "writeText").as("clipboardWrite");
Object.defineProperty(win, "isSecureContext", { value: true, writable: true });
});

cy.realPress(["Control", "c"]);

cy.get("@clipboardWrite").should("have.been.calledOnceWith", "Focused");
});

it("should not cut token in readonly mode", () => {
cy.mount(
<Tokenizer readonly={true}>
<Token text="ReadonlyToken"></Token>
<Token text="Other"></Token>
</Tokenizer>
);

cy.realPress("Tab");
cy.get("[ui5-token]").eq(0).should("have.prop", "focused", true);

cy.window().then((win) => {
cy.stub(win.navigator.clipboard, "writeText").as("clipboardWrite");
Object.defineProperty(win, "isSecureContext", { value: true, writable: true });
});

cy.realPress(["Control", "x"]);

// Should copy but not delete in readonly mode
cy.get("@clipboardWrite").should("have.been.calledOnceWith", "ReadonlyToken");
cy.get("[ui5-token]").should("have.length", 2);
});
});

describe("Tokenizer - getFocusDomRef Method", () => {
Expand Down
12 changes: 8 additions & 4 deletions packages/main/src/Tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -720,10 +720,14 @@ class Tokenizer extends UI5Element implements IFormInputElement {
e.preventDefault();

const isCut = e.key.toLowerCase() === "x" || isDeleteShift(e);
const selectedTokens = this._tokens.filter(token => token.selected);
const focusedToken = selectedTokens.find(token => token.focused);
let selectedTokens = this._tokens.filter(token => token.selected);
const focusedToken = this._tokens.find(token => token.focused);

if (isCut) {
if (!selectedTokens.length && focusedToken) {
selectedTokens = [focusedToken];
}

if (isCut && !this.readonly) {
const cutResult = this._fillClipboard(ClipboardDataOperation.cut, selectedTokens);

focusedToken && this.deleteToken(focusedToken);
Expand Down Expand Up @@ -1079,7 +1083,7 @@ class Tokenizer extends UI5Element implements IFormInputElement {
}

_fillClipboard(shortcutName: ClipboardDataOperation, tokens: Array<IToken>) {
const tokensTexts = tokens.filter(token => token.selected).map(token => token.text).join("\r\n");
const tokensTexts = tokens.map(token => token.text).join("\r\n");

// Async clipboard API (works in secure contexts - HTTPS/localhost)
if (navigator.clipboard?.writeText && window.isSecureContext) {
Expand Down
Loading