gecko-dev/browser/actors/ClickHandlerChild.jsm

145 строки
4.1 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/. */
var EXPORTED_SYMBOLS = ["ClickHandlerChild"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(
this,
"PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"E10SUtils",
"resource://gre/modules/E10SUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
);
class ClickHandlerChild extends JSWindowActorChild {
handleEvent(event) {
if (
!event.isTrusted ||
event.defaultPrevented ||
event.button == 2 ||
(event.type == "click" && event.button == 1)
) {
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;
}
}
let [href, node, principal] = BrowserUtils.hrefAndLinkNodeForClickEvent(
event
);
let csp = ownerDoc.csp;
if (csp) {
csp = E10SUtils.serializeCSP(csp);
}
let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
Ci.nsIReferrerInfo
);
if (node) {
referrerInfo.initWithElement(node);
} else {
referrerInfo.initWithDocument(ownerDoc);
}
referrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo);
let frameID = WebNavigationFrames.getFrameId(ownerDoc.defaultView);
let json = {
button: event.button,
shiftKey: event.shiftKey,
ctrlKey: event.ctrlKey,
metaKey: event.metaKey,
altKey: event.altKey,
href: null,
title: null,
frameID,
triggeringPrincipal: principal,
csp,
referrerInfo,
originAttributes: principal ? principal.originAttributes : {},
isContentWindowPrivate: PrivateBrowsingUtils.isContentWindowPrivate(
ownerDoc.defaultView
),
};
if (href) {
try {
Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
principal,
href
);
} catch (e) {
return;
}
json.href = href;
if (node) {
json.title = node.getAttribute("title");
}
json.originPrincipal = ownerDoc.nodePrincipal;
json.originStoragePrincipal = ownerDoc.effectiveStoragePrincipal;
json.triggeringPrincipal = ownerDoc.nodePrincipal;
// 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.
if (event.button === 1) {
event.preventMultipleActions();
}
this.sendAsyncMessage("Content:Click", json);
return;
}
// This might be middle mouse navigation.
if (event.button == 1) {
this.sendAsyncMessage("Content:Click", json);
}
}
}