Skip to content

Commit

Permalink
Implement commands to locate element by drawing a pattern on it (#443)
Browse files Browse the repository at this point in the history
* Implement mouse movement (wip)

* Finish implementation of drawing and removing locate pattern on element
  • Loading branch information
david-tejada authored Dec 27, 2024
1 parent 8a33728 commit cbb8098
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 7 deletions.
1 change: 1 addition & 0 deletions .xo-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"rules": {
"n/prefer-global/process": "off",
"unicorn/prefer-top-level-await": "off",
"capitalized-comments": "off",
"n/file-extension-in-import": "off",
"import/extensions": [
2,
Expand Down
18 changes: 15 additions & 3 deletions src/background/commands/commandListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,18 @@ export function addCommandListeners() {
}
});

onCommand("drawLocatePattern", async ({ target, colors }) => {
assertPrimitiveTarget(target);
await sendMessageToTargetFrames("drawLocatePattern", {
target,
colors,
});
});

onCommand("removeLocatePattern", async () => {
await sendMessageToAllFrames("removeLocatePattern");
});

onCommand("copyElementTextContent", async ({ target }) => {
const { results } = await sendMessageToTargetFrames(
"getElementTextContent",
Expand Down Expand Up @@ -383,7 +395,7 @@ export function addCommandListeners() {
const message = `Command "focusAndDeleteContents" has been removed. Update rango-talon.`;
await notify.error(message);

return { name: "printError", message };
return { name: "throwError", message };
});

onCommand("focusElement", async ({ target }) => {
Expand Down Expand Up @@ -413,7 +425,7 @@ export function addCommandListeners() {
const message = `Command "insertToField" has been removed. Update rango-talon.`;
await notify.error(message);

return { name: "printError", message };
return { name: "throwError", message };
});

onCommand("openInBackgroundTab", async ({ target }) => {
Expand Down Expand Up @@ -668,7 +680,7 @@ export function addCommandListeners() {
const message = `Command "checkActiveElementIsEditable" has been removed. Update rango-talon.`;
await notify.error(message);

return { name: "printError", message };
return { name: "throwError", message };
});

onCommand("requestTimedOut", async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/background/commands/handleIncomingCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ export async function handleIncomingCommand() {
// Rethrow the error with a more descriptive message.
const message =
"Unable to run command. This command can't run on browser system pages (settings, new tabs, extensions, or other privileged pages).";
await writeResponse({ name: "printError", message });
await writeResponse({ name: "throwError", message });
throw new UnreachableContentScriptError(message);
}

if (error instanceof Error) {
await writeResponse({ name: "printError", message: error.message });
await writeResponse({ name: "throwError", message: error.message });
}

throw error;
Expand Down
67 changes: 67 additions & 0 deletions src/content/actions/locatePattern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { setStyleProperties } from "../dom/setStyleProperties";
import { createElement } from "../dom/utils";
import { type ElementWrapper } from "../wrappers/ElementWrapper";

const squareSize = 3;

export function drawLocatePattern(
wrapper: ElementWrapper,
colors: [number, number, number, number]
) {
const rect = wrapper.element.getClientRects()[0]!;
const { top, left, width, height } =
rect.width > 0 && rect.height > 0
? rect
: wrapper.element.getBoundingClientRect();

const canvas: HTMLCanvasElement =
document.querySelector("#rangoCanvas") ??
createElement("canvas", {
id: "rangoCanvas",
width: squareSize * 2,
height: squareSize * 2,
});

setStyleProperties(canvas, {
position: "fixed",
width: `${(squareSize * 2) / window.devicePixelRatio}px`,
height: `${(squareSize * 2) / window.devicePixelRatio}px`,
top: `${top + height / 2}px`,
left: `${left + width / 2}px`,
"z-index": "2147483647",
"pointer-events": "none",
"image-rendering": "pixelated",
});

const ctx = canvas.getContext("2d")!;

draw4x4Pattern(ctx, colors);

document.body.append(canvas);

setTimeout(() => {
canvas.remove();
}, 1000);
}

export function removeLocatePattern() {
document.querySelector("#rangoCanvas")?.remove();
}

function draw4x4Pattern(
ctx: CanvasRenderingContext2D,
colors: [number, number, number, number]
) {
const hexColors = colors.map(
(n: number) => "#" + n.toString(16).padStart(6, "0")
) as [string, string, string, string];

ctx.fillStyle = hexColors[0];
ctx.fillRect(0, 0, squareSize, squareSize);
ctx.fillStyle = hexColors[1];
ctx.fillRect(squareSize, 0, squareSize, squareSize);
ctx.fillStyle = hexColors[2];
ctx.fillRect(0, squareSize, squareSize, squareSize);
ctx.fillStyle = hexColors[3];
ctx.fillRect(squareSize, squareSize, squareSize, squareSize);
}
5 changes: 4 additions & 1 deletion src/content/dom/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,8 @@ export function createElement<K extends keyof HTMLElementTagNameMap>(
tag: K,
attributes: Partial<HTMLElementTagNameMap[K]>
) {
return Object.assign(document.createElement(tag), attributes);
return Object.assign(
document.createElement(tag),
attributes
) as HTMLElementTagNameMap[K];
}
13 changes: 13 additions & 0 deletions src/content/messaging/messageListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import {
markHintsAsKeyboardReachable,
restoreKeyboardReachableHints,
} from "../actions/keyboardClicking";
import {
drawLocatePattern,
removeLocatePattern,
} from "../actions/locatePattern";
import { matchElementByText } from "../actions/matchElementByText";
import {
navigateToNextPage,
Expand Down Expand Up @@ -132,6 +136,15 @@ export function addMessageListeners() {
return clickElement(wrappers);
});

onMessage("drawLocatePattern", async ({ target, colors }) => {
const wrapper = await getFirstWrapper(target);
drawLocatePattern(wrapper, colors);
});

onMessage("removeLocatePattern", async () => {
removeLocatePattern();
});

onMessage("getElementTextContent", async ({ target }) => {
const wrappers = await getTargetedWrappers(target);
return getElementTextContent(wrappers);
Expand Down
5 changes: 5 additions & 0 deletions src/typings/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ export type ActionMap = {
copyLink: { target: Target<ElementMark> };
copyMarkdownLink: { target: Target<ElementMark> };
directClickElement: { target: Target<ElementMark> };
drawLocatePattern: {
target: Target<ElementMark>;
colors: [number, number, number, number];
};
removeLocatePattern: void;
focusAndDeleteContents: void;
focusElement: { target: Target<ElementMark> };
focusFirstInput: void;
Expand Down
5 changes: 5 additions & 0 deletions src/typings/ProtocolMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ export type ContentBoundMessageMap = {
unhoverAll: () => void;
setSelectionBefore: (data: { target: Target<ElementMark> }) => boolean;
setSelectionAfter: (data: { target: Target<ElementMark> }) => boolean;
drawLocatePattern: (data: {
target: Target<ElementMark>;
colors: [number, number, number, number];
}) => void;
removeLocatePattern: () => void;

// Scroll
scroll: (data: {
Expand Down
2 changes: 1 addition & 1 deletion src/typings/TalonAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type TalonAction =
| TalonActionBase<"focusPageAndResend">
| TalonActionBase<"key", { key: string }>
| TalonActionBase<"openInNewTab", { url: string }>
| TalonActionBase<"printError", { message: string }>
| TalonActionBase<"throwError", { message: string }>
| TalonActionBase<"responseValue", { value: any }>
| TalonActionBase<"sleep", { ms?: number }>
| TalonActionBase<"typeTargetCharacters">;

0 comments on commit cbb8098

Please sign in to comment.