Skip to content

Commit 43e3f21

Browse files
authored
Merge pull request usablica#1152 from usablica/force-position
Adding autoPosition option
2 parents e40846a + 6927345 commit 43e3f21

File tree

4 files changed

+267
-13
lines changed

4 files changed

+267
-13
lines changed

package-lock.json

Lines changed: 13 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/placeTooltip.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,7 @@ function _determineAutoPosition(
135135
}
136136

137137
if (possiblePositions.length) {
138-
if (
139-
desiredTooltipPosition !== "auto" &&
140-
possiblePositions.includes(desiredTooltipPosition)
141-
) {
138+
if (possiblePositions.includes(desiredTooltipPosition)) {
142139
// If the requested position is in the list, choose that
143140
calculatedPosition = desiredTooltipPosition;
144141
} else {
@@ -206,16 +203,16 @@ export default function placeTooltip(
206203
tooltipCssClass = this._options.tooltipClass;
207204
}
208205

209-
tooltipLayer.className = `introjs-tooltip ${tooltipCssClass}`.replace(
210-
/^\s+|\s+$/g,
211-
""
212-
);
206+
tooltipLayer.className = ["introjs-tooltip", tooltipCssClass]
207+
.filter(Boolean)
208+
.join(" ");
209+
213210
tooltipLayer.setAttribute("role", "dialog");
214211

215212
currentTooltipPosition = this._introItems[this._currentStep].position;
216213

217214
// Floating is always valid, no point in calculating
218-
if (currentTooltipPosition !== "floating") {
215+
if (currentTooltipPosition !== "floating" && this._options.autoPosition) {
219216
currentTooltipPosition = _determineAutoPosition.call(
220217
this,
221218
targetElement,

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ function IntroJs(obj) {
7878
scrollPadding: 30,
7979
/* Set the overlay opacity */
8080
overlayOpacity: 0.5,
81+
/* To determine the tooltip position automatically based on the window.width/height */
82+
autoPosition: true,
8183
/* Precedence of positions, when auto is enabled */
8284
positionPrecedence: ["bottom", "top", "right", "left"],
8385
/* Disable an interaction with element? */

tests/core/placeTooltip.test.js

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
import * as getOffset from "../../src/util/getOffset";
2+
import * as getWindowSize from "../../src/util/getWindowSize";
3+
import placeTooltip from "../../src/core/placeTooltip";
4+
5+
describe("placeTooltip", () => {
6+
test("should automatically place the tooltip position when there is enough space", () => {
7+
jest.spyOn(getOffset, "default").mockReturnValue({
8+
height: 100,
9+
width: 100,
10+
top: 0,
11+
left: 0,
12+
});
13+
14+
jest.spyOn(getWindowSize, "default").mockReturnValue({
15+
height: 1000,
16+
width: 1000,
17+
});
18+
19+
jest.spyOn(Element.prototype, "getBoundingClientRect").mockReturnValue({
20+
width: 100,
21+
height: 100,
22+
top: 200,
23+
left: 200,
24+
bottom: 300,
25+
right: 300,
26+
});
27+
28+
const targetElement = document.createElement("div");
29+
const tooltipLayer = document.createElement("div");
30+
const arrowLayer = document.createElement("div");
31+
32+
placeTooltip.call(
33+
{
34+
_currentStep: 0,
35+
_introItems: [
36+
{
37+
tooltip: "hello",
38+
position: "top",
39+
},
40+
],
41+
_options: {
42+
positionPrecedence: ["top", "bottom", "left", "right"],
43+
autoPosition: true,
44+
},
45+
},
46+
targetElement,
47+
tooltipLayer,
48+
arrowLayer,
49+
false
50+
);
51+
52+
expect(tooltipLayer.className).toBe(
53+
"introjs-tooltip introjs-top-right-aligned"
54+
);
55+
});
56+
57+
test("should skip auto positioning when autoPosition is false", () => {
58+
const targetElement = document.createElement("div");
59+
const tooltipLayer = document.createElement("div");
60+
const arrowLayer = document.createElement("div");
61+
62+
placeTooltip.call(
63+
{
64+
_currentStep: 0,
65+
_introItems: [
66+
{
67+
tooltip: "hello",
68+
position: "top",
69+
},
70+
],
71+
_options: {
72+
positionPrecedence: ["top", "bottom"],
73+
autoPosition: false,
74+
},
75+
},
76+
targetElement,
77+
tooltipLayer,
78+
arrowLayer,
79+
false
80+
);
81+
82+
expect(tooltipLayer.className).toBe("introjs-tooltip introjs-top");
83+
});
84+
85+
test("should use floating tooltips when height/width is limited", () => {
86+
jest.spyOn(getOffset, "default").mockReturnValue({
87+
height: 100,
88+
width: 100,
89+
top: 0,
90+
left: 0,
91+
});
92+
93+
jest.spyOn(getWindowSize, "default").mockReturnValue({
94+
height: 100,
95+
width: 100,
96+
});
97+
98+
jest.spyOn(Element.prototype, "getBoundingClientRect").mockReturnValue({
99+
width: 100,
100+
height: 100,
101+
top: 0,
102+
left: 0,
103+
bottom: 0,
104+
right: 0,
105+
});
106+
107+
const targetElement = document.createElement("div");
108+
const tooltipLayer = document.createElement("div");
109+
const arrowLayer = document.createElement("div");
110+
111+
placeTooltip.call(
112+
{
113+
_currentStep: 0,
114+
_introItems: [
115+
{
116+
tooltip: "hello",
117+
position: "left",
118+
},
119+
],
120+
_options: {
121+
positionPrecedence: ["top", "bottom", "left", "right"],
122+
autoPosition: true,
123+
},
124+
},
125+
targetElement,
126+
tooltipLayer,
127+
arrowLayer,
128+
false
129+
);
130+
131+
expect(tooltipLayer.className).toBe("introjs-tooltip introjs-floating");
132+
});
133+
134+
test("should use bottom middle aligned when there is enough vertical space", () => {
135+
jest.spyOn(getOffset, "default").mockReturnValue({
136+
height: 100,
137+
width: 100,
138+
top: 0,
139+
left: 0,
140+
});
141+
142+
jest.spyOn(getWindowSize, "default").mockReturnValue({
143+
height: 500,
144+
width: 100,
145+
});
146+
147+
jest.spyOn(Element.prototype, "getBoundingClientRect").mockReturnValue({
148+
width: 100,
149+
height: 100,
150+
top: 0,
151+
left: 0,
152+
bottom: 0,
153+
right: 0,
154+
});
155+
156+
const targetElement = document.createElement("div");
157+
const tooltipLayer = document.createElement("div");
158+
const arrowLayer = document.createElement("div");
159+
160+
placeTooltip.call(
161+
{
162+
_currentStep: 0,
163+
_introItems: [
164+
{
165+
tooltip: "hello",
166+
position: "left",
167+
},
168+
],
169+
_options: {
170+
positionPrecedence: ["top", "bottom", "left", "right"],
171+
autoPosition: true,
172+
},
173+
},
174+
targetElement,
175+
tooltipLayer,
176+
arrowLayer,
177+
false
178+
);
179+
180+
expect(tooltipLayer.className).toBe(
181+
"introjs-tooltip introjs-bottom-middle-aligned"
182+
);
183+
});
184+
185+
test("should attach the global custom tooltip css class", () => {
186+
const targetElement = document.createElement("div");
187+
const tooltipLayer = document.createElement("div");
188+
const arrowLayer = document.createElement("div");
189+
190+
placeTooltip.call(
191+
{
192+
_currentStep: 0,
193+
_introItems: [
194+
{
195+
tooltip: "hello",
196+
position: "left",
197+
},
198+
],
199+
_options: {
200+
positionPrecedence: ["top", "bottom", "left", "right"],
201+
autoPosition: true,
202+
tooltipClass: "newclass",
203+
},
204+
},
205+
targetElement,
206+
tooltipLayer,
207+
arrowLayer,
208+
false
209+
);
210+
211+
expect(tooltipLayer.className).toBe(
212+
"introjs-tooltip newclass introjs-bottom-middle-aligned"
213+
);
214+
});
215+
216+
test("should attach the step custom tooltip css class", () => {
217+
const targetElement = document.createElement("div");
218+
const tooltipLayer = document.createElement("div");
219+
const arrowLayer = document.createElement("div");
220+
221+
placeTooltip.call(
222+
{
223+
_currentStep: 0,
224+
_introItems: [
225+
{
226+
tooltip: "hello",
227+
position: "left",
228+
tooltipClass: "myclass",
229+
},
230+
],
231+
_options: {
232+
positionPrecedence: ["top", "bottom", "left", "right"],
233+
autoPosition: true,
234+
},
235+
},
236+
targetElement,
237+
tooltipLayer,
238+
arrowLayer,
239+
false
240+
);
241+
242+
expect(tooltipLayer.className).toBe(
243+
"introjs-tooltip myclass introjs-bottom-middle-aligned"
244+
);
245+
});
246+
});

0 commit comments

Comments
 (0)