summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/test/browser_html_tooltip_rtl.js
blob: 11fe3932f3a6434b251ab55b75f134457874cd29 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_html_tooltip.js */
"use strict";

/**
 * Test the HTMLTooltip anchor alignment changes with the anchor direction.
 * - should be aligned to the right of RTL anchors
 * - should be aligned to the left of LTR anchors
 */

const HTML_NS = "http://www.w3.org/1999/xhtml";
const TEST_URI = CHROME_URL_ROOT + "doc_html_tooltip_rtl.xhtml";

const {
  HTMLTooltip,
} = require("resource://devtools/client/shared/widgets/tooltip/HTMLTooltip.js");
loadHelperScript("helper_html_tooltip.js");

const TOOLBOX_WIDTH = 500;
const TOOLTIP_WIDTH = 150;
const TOOLTIP_HEIGHT = 30;

add_task(async function () {
  await pushPref("devtools.toolbox.sidebar.width", TOOLBOX_WIDTH);

  const { doc } = await createHost("right", TEST_URI);

  info("Test the positioning of tooltips in RTL and LTR directions");

  const tooltip = new HTMLTooltip(doc, { useXulWrapper: false });
  const div = doc.createElementNS(HTML_NS, "div");
  div.textContent = "tooltip";
  div.style.cssText = "box-sizing: border-box; border: 1px solid black";
  tooltip.panel.appendChild(div);
  tooltip.setContentSize({ width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT });

  await testRtlAnchors(doc, tooltip);
  await testLtrAnchors(doc, tooltip);
  await hideTooltip(tooltip);

  tooltip.destroy();

  await testRtlArrow(doc);
});

async function testRtlAnchors(doc, tooltip) {
  /*
   * The layout of the test page is as follows:
   *   _______________________________
   *  | toolbox                       |
   *  | _____   _____   _____   _____ |
   *  ||     | |     | |     | |     ||
   *  || box1| | box2| | box3| | box4||
   *  ||_____| |_____| |_____| |_____||
   *  |_______________________________|
   *
   * - box1 is aligned with the left edge of the toolbox
   * - box2 is displayed right after box1
   * - total toolbox width is 500px so each box is 125px wide
   */

  const box1 = doc.getElementById("box1");
  const box2 = doc.getElementById("box2");

  info("Display the tooltip on box1.");
  await showTooltip(tooltip, box1, { position: "bottom" });

  let panelRect = tooltip.container.getBoundingClientRect();
  let anchorRect = box1.getBoundingClientRect();

  // box1 uses RTL direction, so the tooltip should be aligned with the right edge of the
  // anchor, but it is shifted to the right to fit in the toolbox.
  is(panelRect.left, 0, "Tooltip is aligned with left edge of the toolbox");
  is(
    panelRect.top,
    anchorRect.bottom,
    "Tooltip aligned with the anchor bottom edge"
  );
  is(
    panelRect.height,
    TOOLTIP_HEIGHT,
    "Tooltip height is at 100px as expected"
  );

  info("Display the tooltip on box2.");
  await showTooltip(tooltip, box2, { position: "bottom" });

  panelRect = tooltip.container.getBoundingClientRect();
  anchorRect = box2.getBoundingClientRect();

  // box2 uses RTL direction, so the tooltip is aligned with the right edge of the anchor
  is(
    Math.round(panelRect.right),
    Math.round(anchorRect.right),
    "Tooltip is aligned with right edge of anchor"
  );
  is(
    panelRect.top,
    anchorRect.bottom,
    "Tooltip aligned with the anchor bottom edge"
  );
  is(
    panelRect.height,
    TOOLTIP_HEIGHT,
    "Tooltip height is at 100px as expected"
  );
}

async function testLtrAnchors(doc, tooltip) {
  /*
   * The layout of the test page is as follows:
   *   _______________________________
   *  | toolbox                       |
   *  | _____   _____   _____   _____ |
   *  ||     | |     | |     | |     ||
   *  || box1| | box2| | box3| | box4||
   *  ||_____| |_____| |_____| |_____||
   *  |_______________________________|
   *
   * - box3 is is displayed right after box2
   * - box4 is aligned with the right edge of the toolbox
   * - total toolbox width is 500px so each box is 125px wide
   */

  const box3 = doc.getElementById("box3");
  const box4 = doc.getElementById("box4");

  info("Display the tooltip on box3.");
  await showTooltip(tooltip, box3, { position: "bottom" });

  let panelRect = tooltip.container.getBoundingClientRect();
  let anchorRect = box3.getBoundingClientRect();

  // box3 uses LTR direction, so the tooltip is aligned with the left edge of the anchor.
  is(
    Math.round(panelRect.left),
    Math.round(anchorRect.left),
    "Tooltip is aligned with left edge of anchor"
  );
  is(
    panelRect.top,
    anchorRect.bottom,
    "Tooltip aligned with the anchor bottom edge"
  );
  is(
    panelRect.height,
    TOOLTIP_HEIGHT,
    "Tooltip height is at 100px as expected"
  );

  info("Display the tooltip on box4.");
  await showTooltip(tooltip, box4, { position: "bottom" });

  panelRect = tooltip.container.getBoundingClientRect();
  anchorRect = box4.getBoundingClientRect();

  // box4 uses LTR direction, so the tooltip should be aligned with the left edge of the
  // anchor, but it is shifted to the left to fit in the toolbox.
  is(
    panelRect.right,
    TOOLBOX_WIDTH,
    "Tooltip is aligned with right edge of toolbox"
  );
  is(
    panelRect.top,
    anchorRect.bottom,
    "Tooltip aligned with the anchor bottom edge"
  );
  is(
    panelRect.height,
    TOOLTIP_HEIGHT,
    "Tooltip height is at 100px as expected"
  );
}

async function testRtlArrow(doc) {
  // Set up the arrow-style tooltip
  const arrowTooltip = new HTMLTooltip(doc, {
    type: "arrow",
    useXulWrapper: false,
  });
  const div = doc.createElementNS(HTML_NS, "div");
  div.textContent = "tooltip";
  div.style.cssText = "box-sizing: border-box; border: 1px solid black";
  arrowTooltip.panel.appendChild(div);
  arrowTooltip.setContentSize({
    width: TOOLTIP_WIDTH,
    height: TOOLTIP_HEIGHT,
  });

  // box2 uses RTL direction and is far enough from the edge that the arrow
  // should not be squashed in the wrong direction.
  const box2 = doc.getElementById("box2");

  info("Display the arrow tooltip on box2.");
  await showTooltip(arrowTooltip, box2, { position: "top" });

  const arrow = arrowTooltip.arrow;
  ok(arrow, "Tooltip has an arrow");

  const panelRect = arrowTooltip.container.getBoundingClientRect();
  const arrowRect = arrow.getBoundingClientRect();

  // The arrow should be offset from the right edge, but still closer to the
  // right edge than the left edge.
  Assert.less(
    arrowRect.right,
    panelRect.right,
    "Right edge of the arrow " +
      `(${arrowRect.right}) is less than the right edge of the panel ` +
      `(${panelRect.right})`
  );
  const rightMargin = panelRect.right - arrowRect.right;
  const leftMargin = arrowRect.left - panelRect.right;
  Assert.greater(
    rightMargin,
    leftMargin,
    "Arrow should be closer to the right side of " +
      ` the panel (margin: ${rightMargin}) than the left side ` +
      ` (margin: ${leftMargin})`
  );

  await hideTooltip(arrowTooltip);
  arrowTooltip.destroy();
}