mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
130a655906
Differential Revision: https://phabricator.services.mozilla.com/D177027
175 lines
5.5 KiB
JavaScript
175 lines
5.5 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* 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 = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
|
|
E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
|
|
});
|
|
|
|
export class MiddleMousePasteHandlerChild extends JSWindowActorChild {
|
|
handleEvent(clickEvent) {
|
|
if (
|
|
clickEvent.defaultPrevented ||
|
|
clickEvent.button != 1 ||
|
|
MiddleMousePasteHandlerChild.autoscrollEnabled
|
|
) {
|
|
return;
|
|
}
|
|
this.manager
|
|
.getActor("ClickHandler")
|
|
.handleClickEvent(
|
|
clickEvent,
|
|
/* is from middle mouse paste handler */ true
|
|
);
|
|
}
|
|
|
|
onProcessedClick(data) {
|
|
this.sendAsyncMessage("MiddleClickPaste", data);
|
|
}
|
|
}
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
MiddleMousePasteHandlerChild,
|
|
"autoscrollEnabled",
|
|
"general.autoScroll",
|
|
true
|
|
);
|
|
|
|
export class ClickHandlerChild extends JSWindowActorChild {
|
|
handleEvent(wrapperEvent) {
|
|
this.handleClickEvent(wrapperEvent.sourceEvent);
|
|
}
|
|
|
|
handleClickEvent(event, isFromMiddleMousePasteHandler = false) {
|
|
if (event.defaultPrevented || event.button == 2) {
|
|
return;
|
|
}
|
|
// Don't do anything on editable things, we shouldn't open links in
|
|
// contenteditables, and editor needs to possibly handle middlemouse paste
|
|
let composedTarget = event.composedTarget;
|
|
if (
|
|
composedTarget.isContentEditable ||
|
|
(composedTarget.ownerDocument &&
|
|
composedTarget.ownerDocument.designMode == "on") ||
|
|
ChromeUtils.getClassName(composedTarget) == "HTMLInputElement" ||
|
|
ChromeUtils.getClassName(composedTarget) == "HTMLTextAreaElement"
|
|
) {
|
|
return;
|
|
}
|
|
|
|
let originalTarget = event.originalTarget;
|
|
let ownerDoc = originalTarget.ownerDocument;
|
|
if (!ownerDoc) {
|
|
return;
|
|
}
|
|
|
|
// Handle click events from about pages
|
|
if (event.button == 0) {
|
|
if (ownerDoc.documentURI.startsWith("about:blocked")) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// For untrusted events, require a valid transient user gesture activation.
|
|
if (!event.isTrusted && !ownerDoc.hasValidTransientUserGestureActivation) {
|
|
return;
|
|
}
|
|
|
|
let [href, node, principal] =
|
|
lazy.BrowserUtils.hrefAndLinkNodeForClickEvent(event);
|
|
|
|
let csp = ownerDoc.csp;
|
|
if (csp) {
|
|
csp = lazy.E10SUtils.serializeCSP(csp);
|
|
}
|
|
|
|
let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
|
|
Ci.nsIReferrerInfo
|
|
);
|
|
if (node) {
|
|
referrerInfo.initWithElement(node);
|
|
} else {
|
|
referrerInfo.initWithDocument(ownerDoc);
|
|
}
|
|
referrerInfo = lazy.E10SUtils.serializeReferrerInfo(referrerInfo);
|
|
|
|
let json = {
|
|
button: event.button,
|
|
shiftKey: event.shiftKey,
|
|
ctrlKey: event.ctrlKey,
|
|
metaKey: event.metaKey,
|
|
altKey: event.altKey,
|
|
href: null,
|
|
title: null,
|
|
csp,
|
|
referrerInfo,
|
|
};
|
|
|
|
if (href && !isFromMiddleMousePasteHandler) {
|
|
try {
|
|
Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
|
|
principal,
|
|
href
|
|
);
|
|
} catch (e) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
!event.isTrusted &&
|
|
lazy.BrowserUtils.whereToOpenLink(event) != "current"
|
|
) {
|
|
// If we'll open the link, we want to consume the user gesture
|
|
// activation to ensure that we don't allow multiple links to open
|
|
// from one user gesture.
|
|
// Avoid doing so for links opened in the current tab, which get
|
|
// handled later, by gecko, as otherwise its popup blocker will stop
|
|
// the link from opening.
|
|
// We will do the same check (whereToOpenLink) again in the parent and
|
|
// avoid handling the click for such links... but we still need the
|
|
// click information in the parent because otherwise places link
|
|
// tracking breaks. (bug 1742894 tracks improving this.)
|
|
ownerDoc.consumeTransientUserGestureActivation();
|
|
// We don't care about the return value because we already checked that
|
|
// hasValidTransientUserGestureActivation was true earlier in this
|
|
// function.
|
|
}
|
|
|
|
json.href = href;
|
|
if (node) {
|
|
json.title = node.getAttribute("title");
|
|
}
|
|
|
|
if (
|
|
(ownerDoc.URL === "about:newtab" || ownerDoc.URL === "about:home") &&
|
|
node.dataset.isSponsoredLink === "true"
|
|
) {
|
|
json.globalHistoryOptions = { triggeringSponsoredURL: href };
|
|
}
|
|
|
|
// If a link element is clicked with middle button, user wants to open
|
|
// the link somewhere rather than pasting clipboard content. Therefore,
|
|
// when it's clicked with middle button, we should prevent multiple
|
|
// actions here to avoid leaking clipboard content unexpectedly.
|
|
// Note that whether the link will work actually or not does not matter
|
|
// because in this case, user does not intent to paste clipboard content.
|
|
// We also need to do this to prevent multiple tabs opening if there are
|
|
// nested link elements.
|
|
event.preventMultipleActions();
|
|
|
|
this.sendAsyncMessage("Content:Click", json);
|
|
}
|
|
|
|
// This might be middle mouse navigation, in which case pass this back:
|
|
if (!href && event.button == 1 && isFromMiddleMousePasteHandler) {
|
|
this.manager.getActor("MiddleMousePasteHandler").onProcessedClick(json);
|
|
}
|
|
}
|
|
}
|