Files
tubestation/browser/components/genai/GenAIChild.sys.mjs
Ed Lee de85a49a56 Bug 1912564 - More shortcuts triggering and hiding improvements r=tarek
Check for selection change instead of just having a selection. Support inputs/textarea selection. Hide before unload.

Differential Revision: https://phabricator.services.mozilla.com/D219105
2024-08-14 10:53:09 +00:00

111 lines
3.1 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"shortcutsDelay",
"browser.ml.chat.shortcuts.longPress"
);
// Additional events to listen with others to create the actor in BrowserGlue
const EVENTS = ["mousedown", "mouseup", "pagehide"];
/**
* JSWindowActor to detect content page events to send GenAI related data.
*/
export class GenAIChild extends JSWindowActorChild {
actorCreated() {
this.document.addEventListener("selectionchange", this);
// Use capture as some pages might stop the events
EVENTS.forEach(ev => this.contentWindow.addEventListener(ev, this, true));
}
didDestroy() {
this.document.removeEventListener("selectionchange", this);
EVENTS.forEach(ev =>
this.contentWindow?.removeEventListener(ev, this, true)
);
}
handleEvent(event) {
const sendHide = () =>
this.sendAsyncMessage("GenAI:HideShortcuts", event.type);
switch (event.type) {
case "mousedown":
this.downSelection = this.getSelectionInfo().selection;
this.downTime = Date.now();
sendHide();
break;
case "mouseup": {
// Only handle plain clicks
if (
event.button ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey
) {
return;
}
// Show immediately on selection or allow long press with no selection
const selectionInfo = this.getSelectionInfo();
const delay = Date.now() - (this.downTime ?? 0);
if (
(selectionInfo.selection &&
selectionInfo.selection != this.downSelection) ||
delay > lazy.shortcutsDelay
) {
this.sendAsyncMessage("GenAI:ShowShortcuts", {
...selectionInfo,
delay,
x: event.screenX,
y: event.screenY,
});
}
break;
}
case "pagehide":
case "resize":
case "scroll":
case "selectionchange":
// Hide if selection might have shifted away from shortcuts
sendHide();
break;
}
}
/**
* Provide the selected text and input type.
*
* @returns {object} selection info
*/
getSelectionInfo() {
// Handle regular selection outside of inputs
const { activeElement } = this.document;
const selection = this.contentWindow.getSelection()?.toString().trim();
if (selection) {
return {
inputType: activeElement.closest("[contenteditable]")
? "contenteditable"
: "",
selection,
};
}
// Selection within input elements
const { selectionStart, value } = activeElement;
if (selectionStart != null && value != null) {
return {
inputType: activeElement.localName,
selection: value.slice(selectionStart, activeElement.selectionEnd),
};
}
return { inputType: "", selection: "" };
}
}