1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 var EXPORTED_SYMBOLS = ["ClickHandlerChild", "MiddleMousePasteHandlerChild"];
8 const { XPCOMUtils } = ChromeUtils.importESModule(
9 "resource://gre/modules/XPCOMUtils.sys.mjs"
14 ChromeUtils.defineModuleGetter(
16 "PrivateBrowsingUtils",
17 "resource://gre/modules/PrivateBrowsingUtils.jsm"
19 ChromeUtils.defineModuleGetter(
21 "WebNavigationFrames",
22 "resource://gre/modules/WebNavigationFrames.jsm"
24 ChromeUtils.defineModuleGetter(
27 "resource://gre/modules/E10SUtils.jsm"
30 ChromeUtils.defineModuleGetter(
33 "resource://gre/modules/BrowserUtils.jsm"
36 class MiddleMousePasteHandlerChild extends JSWindowActorChild {
37 handleEvent(clickEvent) {
39 clickEvent.defaultPrevented ||
40 clickEvent.button != 1 ||
41 MiddleMousePasteHandlerChild.autoscrollEnabled
46 .getActor("ClickHandler")
49 /* is from middle mouse paste handler */ true
53 onProcessedClick(data) {
54 this.sendAsyncMessage("MiddleClickPaste", data);
58 XPCOMUtils.defineLazyPreferenceGetter(
59 MiddleMousePasteHandlerChild,
65 class ClickHandlerChild extends JSWindowActorChild {
66 handleEvent(wrapperEvent) {
67 this.handleClickEvent(wrapperEvent.sourceEvent);
70 handleClickEvent(event, isFromMiddleMousePasteHandler = false) {
71 if (event.defaultPrevented || event.button == 2) {
74 // Don't do anything on editable things, we shouldn't open links in
75 // contenteditables, and editor needs to possibly handle middlemouse paste
76 let composedTarget = event.composedTarget;
78 composedTarget.isContentEditable ||
79 (composedTarget.ownerDocument &&
80 composedTarget.ownerDocument.designMode == "on") ||
81 ChromeUtils.getClassName(composedTarget) == "HTMLInputElement" ||
82 ChromeUtils.getClassName(composedTarget) == "HTMLTextAreaElement"
87 let originalTarget = event.originalTarget;
88 let ownerDoc = originalTarget.ownerDocument;
93 // Handle click events from about pages
94 if (event.button == 0) {
95 if (ownerDoc.documentURI.startsWith("about:blocked")) {
100 // For untrusted events, require a valid transient user gesture activation.
101 if (!event.isTrusted && !ownerDoc.hasValidTransientUserGestureActivation) {
109 ] = lazy.BrowserUtils.hrefAndLinkNodeForClickEvent(event);
111 let csp = ownerDoc.csp;
113 csp = lazy.E10SUtils.serializeCSP(csp);
116 let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
120 referrerInfo.initWithElement(node);
122 referrerInfo.initWithDocument(ownerDoc);
124 referrerInfo = lazy.E10SUtils.serializeReferrerInfo(referrerInfo);
125 let frameID = lazy.WebNavigationFrames.getFrameId(ownerDoc.defaultView);
128 button: event.button,
129 shiftKey: event.shiftKey,
130 ctrlKey: event.ctrlKey,
131 metaKey: event.metaKey,
132 altKey: event.altKey,
136 triggeringPrincipal: principal,
139 originAttributes: principal ? principal.originAttributes : {},
140 isContentWindowPrivate: lazy.PrivateBrowsingUtils.isContentWindowPrivate(
145 if (href && !isFromMiddleMousePasteHandler) {
147 Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
157 lazy.BrowserUtils.whereToOpenLink(event) != "current"
159 // If we'll open the link, we want to consume the user gesture
160 // activation to ensure that we don't allow multiple links to open
161 // from one user gesture.
162 // Avoid doing so for links opened in the current tab, which get
163 // handled later, by gecko, as otherwise its popup blocker will stop
164 // the link from opening.
165 // We will do the same check (whereToOpenLink) again in the parent and
166 // avoid handling the click for such links... but we still need the
167 // click information in the parent because otherwise places link
168 // tracking breaks. (bug 1742894 tracks improving this.)
169 ownerDoc.consumeTransientUserGestureActivation();
170 // We don't care about the return value because we already checked that
171 // hasValidTransientUserGestureActivation was true earlier in this
177 json.title = node.getAttribute("title");
180 json.originPrincipal = ownerDoc.nodePrincipal;
181 json.originStoragePrincipal = ownerDoc.effectiveStoragePrincipal;
182 json.triggeringPrincipal = ownerDoc.nodePrincipal;
185 (ownerDoc.URL === "about:newtab" || ownerDoc.URL === "about:home") &&
186 node.dataset.isSponsoredLink === "true"
188 json.globalHistoryOptions = { triggeringSponsoredURL: href };
191 // If a link element is clicked with middle button, user wants to open
192 // the link somewhere rather than pasting clipboard content. Therefore,
193 // when it's clicked with middle button, we should prevent multiple
194 // actions here to avoid leaking clipboard content unexpectedly.
195 // Note that whether the link will work actually or not does not matter
196 // because in this case, user does not intent to paste clipboard content.
197 // We also need to do this to prevent multiple tabs opening if there are
198 // nested link elements.
199 event.preventMultipleActions();
201 this.sendAsyncMessage("Content:Click", json);
204 // This might be middle mouse navigation, in which case pass this back:
205 if (!href && event.button == 1 && isFromMiddleMousePasteHandler) {
206 this.manager.getActor("MiddleMousePasteHandler").onProcessedClick(json);