Skip to content

Commit ba7f9a0

Browse files
committed
[frontend] add context menu handler to page inject
1 parent 3bbe01c commit ba7f9a0

File tree

4 files changed

+210
-228
lines changed

4 files changed

+210
-228
lines changed

packages/chrome/src/IsolatedFrame.tsx

Lines changed: 159 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,20 @@ import { ElementType, type Handler, Parser } from "htmlparser2";
1515
import { type ChildNode, DomHandler, Element, Comment, Node } from "domhandler";
1616
import * as tldts from "tldts";
1717

18-
import type {
19-
Chromebound,
20-
ChromeboundMethods,
21-
Framebound,
22-
FrameboundMethods,
23-
} from "../../inject/src/types";
18+
import iconBack from "@ktibow/iconset-ion/arrow-back";
19+
import iconForwards from "@ktibow/iconset-ion/arrow-forward";
20+
import iconRefresh from "@ktibow/iconset-ion/refresh";
21+
import iconBookmark from "@ktibow/iconset-ion/bookmark-outline";
22+
import iconCode from "@ktibow/iconset-ion/code-outline";
23+
import iconLink from "@ktibow/iconset-ion/link-outline";
24+
import iconAdd from "@ktibow/iconset-ion/duplicate-outline";
25+
import iconCopy from "@ktibow/iconset-ion/copy-outline";
26+
import iconSave from "@ktibow/iconset-ion/save-outline";
27+
28+
import type { Chromebound, Framebound } from "../../inject/src/types";
2429
import type { Tab } from "./Tab";
2530
import { browser } from "./Browser";
31+
import { createMenu } from "./components/Menu";
2632

2733
const ISOLATION_ORIGIN = import.meta.env.VITE_ISOLATION_ORIGIN;
2834

@@ -436,6 +442,142 @@ type ChromeboundMethods = {
436442
) => Promise<Chromebound[K][1]>;
437443
};
438444

445+
function pageContextItems(
446+
tab: Tab,
447+
{ selection, image, anchor }: Chromebound["contextmenu"][0]
448+
) {
449+
if (selection && selection.toString().length > 0) {
450+
return [
451+
{
452+
label: "Search",
453+
action: () => {
454+
const query = selection.toString();
455+
if (query) {
456+
tab.pushNavigate(
457+
new URL(
458+
`https://www.google.com/search?q=${encodeURIComponent(query)}`
459+
)
460+
);
461+
}
462+
},
463+
},
464+
{
465+
label: "Copy",
466+
action: () => {
467+
navigator.clipboard.writeText(selection.toString());
468+
},
469+
},
470+
];
471+
}
472+
473+
if (image) {
474+
return [
475+
{
476+
label: "Open Image in New Tab",
477+
action: () => {
478+
// TODO: this is broken lol
479+
if (image.src) {
480+
let newTab = browser.newTab();
481+
newTab.pushNavigate(new URL(image.src));
482+
}
483+
},
484+
},
485+
{
486+
label: "Copy Image URL",
487+
action: () => {
488+
navigator.clipboard.writeText(image.src);
489+
},
490+
},
491+
{
492+
label: "Copy Image",
493+
action: () => {
494+
// copyImageToClipboard(target);
495+
},
496+
},
497+
{
498+
label: "Save Image As...",
499+
action: () => {
500+
// TODO
501+
},
502+
},
503+
];
504+
} else if (anchor) {
505+
return [
506+
{
507+
label: "Open Link",
508+
action: () => {
509+
if (anchor.href) {
510+
browser.activetab.pushNavigate(new URL(anchor.href));
511+
}
512+
},
513+
icon: iconLink,
514+
},
515+
{
516+
label: "Open Link in New Tab",
517+
action: () => {
518+
if (anchor.href) {
519+
browser.newTab(new URL(anchor.href));
520+
}
521+
},
522+
icon: iconAdd,
523+
},
524+
{
525+
label: "Copy Link Address",
526+
action: () => {
527+
navigator.clipboard.writeText(anchor.href);
528+
},
529+
icon: iconCopy,
530+
},
531+
{
532+
label: "Save Link As...",
533+
action: () => {
534+
// TODO
535+
},
536+
icon: iconSave,
537+
},
538+
];
539+
}
540+
541+
return [
542+
{
543+
label: "Back",
544+
action: () => {
545+
tab.back();
546+
},
547+
icon: iconBack,
548+
},
549+
{
550+
label: "Forward",
551+
action: () => {
552+
tab.forward();
553+
},
554+
icon: iconForwards,
555+
},
556+
{
557+
label: "Reload",
558+
action: () => {
559+
tab.reload();
560+
},
561+
icon: iconRefresh,
562+
},
563+
{
564+
label: "Bookmark",
565+
action: () => {
566+
// TODO:
567+
console.log("Bookmarking", tab.title, tab.url);
568+
},
569+
icon: iconBookmark,
570+
},
571+
{
572+
label: "Inspect",
573+
action: () => {
574+
tab.devtoolsOpen = true;
575+
// if (e.target) requestInspectElement([e.target as HTMLElement, tab]);
576+
},
577+
icon: iconCode,
578+
},
579+
];
580+
}
439581
const chromemethods: ChromeboundMethods = {
440582
titlechange: async (tab, { title, icon }) => {
441583
console.log("title changed...", tab, title, icon);
@@ -450,5 +592,15 @@ const chromemethods: ChromeboundMethods = {
450592
}
451593
}
452594
},
453-
contextmenu: async (controller, { x, y }) => {},
595+
contextmenu: async (tab, msg) => {
596+
let offX = 0;
597+
let offY = 0;
598+
let { x, y } = tab!.frame.frame.getBoundingClientRect();
599+
offX += x;
600+
offY += y;
601+
createMenu(
602+
{ left: msg.x + offX, top: msg.y + offY },
603+
pageContextItems(tab!, msg)
604+
);
605+
},
454606
};

0 commit comments

Comments
 (0)