summaryrefslogtreecommitdiffstats
path: root/toolkit/components/satchel/FillHelpers.sys.mjs
blob: fd335f271ee180027152897740b515dffc8eba46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* 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/. */

// This item shows image, title & subtitle.
// Once selected it will send fillMessageName with fillMessageData
// to the parent actor and response will be used to fill into the field.
export class GenericAutocompleteItem {
  comment = "";
  style = "generic";
  value = "";

  constructor(image, title, subtitle, fillMessageName, fillMessageData) {
    this.image = image;
    this.comment = JSON.stringify({
      title,
      subtitle,
      fillMessageName,
      fillMessageData,
    });
  }
}

/**
 * Show confirmation tooltip
 *
 * @param {object} browser - An object representing the browser.
 * @param {string} messageId - Message ID from browser/confirmationHints.ftl
 * @param {string} [anchorId="identity-icon-box"] - ID of the element to anchor the hint to.
                   The "password-notification-icon" and "notification-popup-box" are hidden
                   at the point of showing the hint (for *most* cases), so approximate the
                   location with the next closest, visible icon as the anchor.
 */
export function showConfirmation(
  browser,
  messageId,
  anchorId = "identity-icon-box"
) {
  const anchor = browser.ownerDocument.getElementById(anchorId);
  anchor.ownerGlobal.ConfirmationHint.show(anchor, messageId, {});
}

let fillRequestId = 0;

/**
 * Send a message encoded in the comment from an autocomplete item
 * to the parent.
 *
 * @param {string} actorName name of the actor to send to
 * @param {object} autocompleteInput current nsIAutoCompleteInput
 * @param {string} comment serialized JSON comment containing fillMessageName and
 *                         fillMessageData to send to the actor
 */
export async function sendFillRequestToParent(
  actorName,
  autocompleteInput,
  comment
) {
  if (!comment) {
    return;
  }

  const { fillMessageName, fillMessageData } = JSON.parse(comment);
  if (!fillMessageName) {
    return;
  }

  fillRequestId++;
  const currentFillRequestId = fillRequestId;
  const actor =
    autocompleteInput.focusedInput.ownerGlobal?.windowGlobalChild?.getActor(
      actorName
    );
  const value = await actor.sendQuery(fillMessageName, fillMessageData ?? {});

  // skip fill if another fill operation started during await
  if (currentFillRequestId != fillRequestId) {
    return;
  }

  if (typeof value !== "string") {
    return;
  }

  // If the parent returned a string to fill, we must do it here because
  // nsAutoCompleteController.cpp already finished it's work before we finished await.
  autocompleteInput.textValue = value;
  autocompleteInput.selectTextRange(value.length, value.length);
}