summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/changes/ChangesContextMenu.js
blob: 40257ec898477bf9b27007b1045e7ce5ad2d4443 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* 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/. */

"use strict";

const Menu = require("resource://devtools/client/framework/menu.js");
loader.lazyRequireGetter(
  this,
  "MenuItem",
  "resource://devtools/client/framework/menu-item.js"
);

const {
  getStr,
} = require("resource://devtools/client/inspector/changes/utils/l10n.js");

/**
 * Context menu for the Changes panel with options to select, copy and export CSS changes.
 */
class ChangesContextMenu extends Menu {
  constructor(config = {}) {
    super(config);
    this.onCopy = config.onCopy;
    this.onCopyAllChanges = config.onCopyAllChanges;
    this.onCopyDeclaration = config.onCopyDeclaration;
    this.onCopyRule = config.onCopyRule;
    this.onSelectAll = config.onSelectAll;
    this.toolboxDocument = config.toolboxDocument;
    this.window = config.window;
  }

  show(event) {
    this._openMenu({
      target: event.target,
      screenX: event.screenX,
      screenY: event.screenY,
    });
  }

  _openMenu({ target, screenX = 0, screenY = 0 } = {}) {
    this.window.focus();
    // Remove existing menu items.
    this.clear();

    // Copy option
    const menuitemCopy = new MenuItem({
      id: "changes-contextmenu-copy",
      label: getStr("changes.contextmenu.copy"),
      accesskey: getStr("changes.contextmenu.copy.accessKey"),
      click: this.onCopy,
      disabled: !this._hasTextSelected(),
    });
    this.append(menuitemCopy);

    const declEl = target.closest(".changes__declaration");
    const ruleEl = target.closest("[data-rule-id]");
    const ruleId = ruleEl ? ruleEl.dataset.ruleId : null;

    if (ruleId || declEl) {
      // Copy Rule option
      this.append(
        new MenuItem({
          id: "changes-contextmenu-copy-rule",
          label: getStr("changes.contextmenu.copyRule"),
          click: () => this.onCopyRule(ruleId, true),
        })
      );

      // Copy Declaration option. Visible only if there is a declaration element target.
      this.append(
        new MenuItem({
          id: "changes-contextmenu-copy-declaration",
          label: getStr("changes.contextmenu.copyDeclaration"),
          click: () => this.onCopyDeclaration(declEl),
          visible: !!declEl,
        })
      );

      this.append(
        new MenuItem({
          type: "separator",
        })
      );
    }

    // Select All option
    const menuitemSelectAll = new MenuItem({
      id: "changes-contextmenu-select-all",
      label: getStr("changes.contextmenu.selectAll"),
      accesskey: getStr("changes.contextmenu.selectAll.accessKey"),
      click: this.onSelectAll,
    });
    this.append(menuitemSelectAll);

    this.popup(screenX, screenY, this.toolboxDocument);
  }

  _hasTextSelected() {
    const selection = this.window.getSelection();
    return selection.toString() && !selection.isCollapsed;
  }

  destroy() {
    this.window = null;
    this.toolboxDocument = null;
  }
}

module.exports = ChangesContextMenu;