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
21 changes: 21 additions & 0 deletions litmus/bugs/link-target.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Link and LinkButton with a local href and a target other than _self. The browser should follow
// them: _blank opens a new tab, a named target opens (and then reuses) a tab with that name, and
// the url shown below stays the same. A link without a target navigates inside the app.
//
// Run: import Demo from "./bugs/link-target"; in litmus/index.js
import { Link, LinkButton } from "cx/widgets";

export default (
<cx>
<div style="padding: 20px; display: flex; flex-direction: column; gap: 12px; align-items: flex-start">
<div>
<b>Current url:</b> <span text-bind="url" style="font-family: monospace" />
</div>
<Link href="~/reports" text="Link, no target (stays in this tab)" />
<Link href="~/reports" target="_blank" text='Link, target="_blank"' />
<Link href="~/reports" target="report" text='Link, target="report" (named window)' />
<LinkButton href="~/reports" target="_blank" text='LinkButton, target="_blank"' />
<Link href="~/" text="Back to ~/" />
</div>
</cx>
);
3 changes: 2 additions & 1 deletion litmus/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ import "./index.scss";
// import Demo from "./features/charts/line-graph/LineGraph";
// import Demo from "./features/charts/line-graph/SmoothingOvershoot";
//import Demo from "./features/window/resize-cursor";
import Demo from "./features/dropdown/lookup-inside-iframe-portal";
// import Demo from "./features/dropdown/lookup-inside-iframe-portal";
import Demo from "./bugs/link-target";
// import Demo from "./features/dropdown/lookup-inside-real-iframe";
// import Demo from "./features/dropdown/context-menu-iframe-focus";
// import Demo from "./bugs/GridDefaultSortFieldClearableSortIssue";
Expand Down
41 changes: 41 additions & 0 deletions packages/cx/src/widgets/nav/Link.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Link } from "./Link";
import { Store } from "../../data/Store";
import { History } from "../../ui/app/History";
import { createModel } from "../../data/createAccessorModelProxy";
import { createTestRenderer } from "../../util/test/createTestRenderer";
import assert from "assert";
Expand Down Expand Up @@ -110,6 +111,46 @@ describe("Link", () => {
});
});

describe("click on a local href", () => {
let pushState = History.pushState;
let pushed: string[];

beforeEach(() => {
pushed = [];
History.pushState = (state, title, url) => {
pushed.push(url);
return true;
};
});

afterEach(() => {
History.pushState = pushState;
});

async function click(target?: string) {
let store = new Store();
let component = await createTestRenderer(
store,
<cx>
<Link href="~/reports" target={target} text="Reports" />
</cx>,
);
let prevented = false;
findAnchor(component.toJSON()).props.onClick({ preventDefault: () => (prevented = true) });
return prevented;
}

it("navigates in the app without a target", async () => {
assert.equal(await click(), true);
assert.deepEqual(pushed, ["/reports"]);
});

it("leaves target=_blank to the browser", async () => {
assert.equal(await click("_blank"), false);
assert.deepEqual(pushed, []);
});
});

describe("active override", () => {
it("true wins over a non-matching url", async () => {
assert.equal(await isActive("~/other", { href: "~/items", active: true }), true);
Expand Down
9 changes: 8 additions & 1 deletion packages/cx/src/widgets/nav/LinkButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,14 @@ export class LinkButton extends Button {

if (this.onClick && instance.invoke("onClick", e, instance) === false) return;

if (data.href && Url.isLocal(data.href) && !e.ctrlKey && !e.shiftKey && !e.metaKey) {
if (
data.href &&
Url.isLocal(data.href) &&
(!data.target || data.target === "_self") &&
!e.ctrlKey &&
!e.shiftKey &&
!e.metaKey
) {
e.preventDefault();
History.pushState({}, null, data.href);
}
Expand Down
Loading