@@ -15,14 +15,20 @@ import { ElementType, type Handler, Parser } from "htmlparser2";
1515import { type ChildNode , DomHandler , Element , Comment , Node } from "domhandler" ;
1616import * 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" ;
2429import type { Tab } from "./Tab" ;
2530import { browser } from "./Browser" ;
31+ import { createMenu } from "./components/Menu" ;
2632
2733const 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+ }
439581const 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