1/* -*- mode: js; 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/. */
5
6"use strict";
7
8var EXPORTED_SYMBOLS = ["ClickHandlerParent", "MiddleMousePasteHandlerParent"];
9
10ChromeUtils.defineModuleGetter(
11  this,
12  "PlacesUIUtils",
13  "resource:///modules/PlacesUIUtils.jsm"
14);
15ChromeUtils.defineModuleGetter(
16  this,
17  "PrivateBrowsingUtils",
18  "resource://gre/modules/PrivateBrowsingUtils.jsm"
19);
20ChromeUtils.defineModuleGetter(
21  this,
22  "E10SUtils",
23  "resource://gre/modules/E10SUtils.jsm"
24);
25
26let gContentClickListeners = new Set();
27
28class MiddleMousePasteHandlerParent extends JSWindowActorParent {
29  receiveMessage(message) {
30    if (message.name == "MiddleClickPaste") {
31      // This is heavily based on contentAreaClick from browser.js (Bug 903016)
32      // The data is set up in a way to look like an Event.
33      let browser = this.manager.browsingContext.top.embedderElement;
34      if (!browser) {
35        // Can be null if the tab disappeared by the time we got the message.
36        // Just bail.
37        return;
38      }
39      browser.ownerGlobal.middleMousePaste(message.data);
40    }
41  }
42}
43
44class ClickHandlerParent extends JSWindowActorParent {
45  static addContentClickListener(listener) {
46    gContentClickListeners.add(listener);
47  }
48
49  static removeContentClickListener(listener) {
50    gContentClickListeners.delete(listener);
51  }
52
53  receiveMessage(message) {
54    switch (message.name) {
55      case "Content:Click":
56        this.contentAreaClick(message.data);
57        this.notifyClickListeners(message.data);
58        break;
59    }
60  }
61
62  /**
63   * Handles clicks in the content area.
64   *
65   * @param data {Object} object that looks like an Event
66   * @param browser {Element<browser>}
67   */
68  contentAreaClick(data) {
69    // This is heavily based on contentAreaClick from browser.js (Bug 903016)
70    // The data is set up in a way to look like an Event.
71    let browser = this.manager.browsingContext.top.embedderElement;
72    if (!browser) {
73      // Can be null if the tab disappeared by the time we got the message.
74      // Just bail.
75      return;
76    }
77    let window = browser.ownerGlobal;
78
79    // If the browser is not in a place where we can open links, bail out.
80    // This can happen in osx sheets, dialogs, etc. that are not browser
81    // windows.  Specifically the payments UI is in an osx sheet.
82    if (window.openLinkIn === undefined) {
83      return;
84    }
85
86    // Mark the page as a user followed link.  This is done so that history can
87    // distinguish automatic embed visits from user activated ones.  For example
88    // pages loaded in frames are embed visits and lost with the session, while
89    // visits across frames should be preserved.
90    try {
91      if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
92        PlacesUIUtils.markPageAsFollowedLink(data.href);
93      }
94    } catch (ex) {
95      /* Skip invalid URIs. */
96    }
97
98    // This part is based on handleLinkClick.
99    var where = window.whereToOpenLink(data);
100    if (where == "current") {
101      return;
102    }
103
104    // Todo(903022): code for where == save
105
106    let params = {
107      charset: browser.characterSet,
108      referrerInfo: E10SUtils.deserializeReferrerInfo(data.referrerInfo),
109      isContentWindowPrivate: data.isContentWindowPrivate,
110      originPrincipal: data.originPrincipal,
111      originStoragePrincipal: data.originStoragePrincipal,
112      triggeringPrincipal: data.triggeringPrincipal,
113      csp: data.csp ? E10SUtils.deserializeCSP(data.csp) : null,
114      frameID: data.frameID,
115      openerBrowser: browser,
116    };
117
118    // The new tab/window must use the same userContextId.
119    if (data.originAttributes.userContextId) {
120      params.userContextId = data.originAttributes.userContextId;
121    }
122
123    params.allowInheritPrincipal = true;
124
125    window.openLinkIn(data.href, where, params);
126  }
127
128  notifyClickListeners(data) {
129    for (let listener of gContentClickListeners) {
130      try {
131        let browser = this.browsingContext.top.embedderElement;
132
133        listener.onContentClick(browser, data);
134      } catch (ex) {
135        Cu.reportError(ex);
136      }
137    }
138  }
139}
140