Skip to content

Commit eb138b7

Browse files
authored
fix: make dashboard draggables work on firefox (#7880)
1 parent a1368a4 commit eb138b7

File tree

5 files changed

+78
-23
lines changed

5 files changed

+78
-23
lines changed

packages/dashboard/src/vaadin-dashboard-helpers.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ export function getItemsArrayOfItem(item, items) {
4747
* @param {HTMLElement} element the element
4848
*/
4949
export function getElementItem(element) {
50-
return element.closest(WRAPPER_LOCAL_NAME).__item;
50+
const wrapper = element.closest(WRAPPER_LOCAL_NAME);
51+
return wrapper && wrapper.__item;
5152
}
5253

5354
/**

packages/dashboard/src/vaadin-dashboard-item-mixin.js

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,16 @@ export const DashboardItemMixin = (superClass) =>
9292

9393
/** @private */
9494
__renderDragHandle() {
95-
return html`<button
96-
aria-label="${this.__i18n.move}"
97-
title="${this.__i18n.move}"
98-
id="drag-handle"
99-
draggable="true"
100-
class="drag-handle"
101-
tabindex="${this.__selected ? 0 : -1}"
102-
@click="${() => this.__enterMoveMode()}"
103-
></button>`;
95+
// To make the button draggable on Firefox, using a workaround from https://stackoverflow.com/a/55019027/3409629
96+
return html`<label draggable="true" class="drag-handle" id="drag-handle-wrapper">
97+
<button
98+
id="drag-handle"
99+
aria-label="${this.__i18n.move}"
100+
title="${this.__i18n.move}"
101+
tabindex="${this.__selected ? 0 : -1}"
102+
@click="${() => this.__enterMoveMode()}"
103+
></button>
104+
</label>`;
104105
}
105106

106107
/** @private */
@@ -116,17 +117,18 @@ export const DashboardItemMixin = (superClass) =>
116117

117118
/** @private */
118119
__renderFocusButton(i18nSelectTitleForEditingProperty) {
119-
return html`<button
120-
aria-label=${this.__i18n[i18nSelectTitleForEditingProperty]}
121-
aria-describedby="title"
122-
aria-pressed="${!!this.__selected}"
123-
id="focus-button"
124-
draggable="true"
125-
class="drag-handle"
126-
@click="${() => {
127-
this.__selected = true;
128-
}}"
129-
></button>`;
120+
// To make the button draggable on Firefox, using a workaround from https://stackoverflow.com/a/55019027/3409629
121+
return html`<label draggable="true" class="drag-handle" id="focus-button-wrapper">
122+
<button
123+
id="focus-button"
124+
aria-label=${this.__i18n[i18nSelectTitleForEditingProperty]}
125+
aria-describedby="title"
126+
aria-pressed="${!!this.__selected}"
127+
@click="${() => {
128+
this.__selected = true;
129+
}}"
130+
></button>
131+
</label>`;
130132
}
131133

132134
/** @private */

packages/dashboard/src/vaadin-dashboard-styles.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,28 @@ export const dashboardWidgetAndSectionStyles = css`
4343
align-items: center;
4444
}
4545
46+
#focus-button-wrapper,
4647
#focus-button {
4748
position: absolute;
4849
inset: 0;
4950
opacity: 0;
5051
}
5152
53+
#focus-button {
54+
pointer-events: none;
55+
padding: 0;
56+
border: none;
57+
}
58+
59+
#drag-handle-wrapper {
60+
z-index: 1;
61+
cursor: grab;
62+
}
63+
5264
#drag-handle {
5365
font-size: 30px;
54-
cursor: grab;
5566
z-index: 1;
67+
pointer-events: none;
5668
}
5769
5870
#drag-handle::before {

packages/dashboard/src/vaadin-dashboard.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab
360360

361361
/** @private */
362362
__dispatchCustomEvent(eventName, item, value) {
363+
if (!item) {
364+
return;
365+
}
363366
this.dispatchEvent(
364367
new CustomEvent(eventName, {
365368
detail: {

packages/dashboard/test/dashboard-widget-reordering.test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { expect } from '@vaadin/chai-plugins';
2-
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers';
2+
import { fixtureSync, isFirefox, nextFrame } from '@vaadin/testing-helpers';
3+
import { resetMouse, sendMouse } from '@web/test-runner-commands';
34
import sinon from 'sinon';
45
import '../vaadin-dashboard.js';
6+
import { hover } from '../../button/test/visual/helpers.js';
57
import type { Dashboard, DashboardItem, DashboardSectionItem } from '../vaadin-dashboard.js';
68
import {
79
createDragEvent,
@@ -56,6 +58,10 @@ describe('dashboard - widget reordering', () => {
5658
]);
5759
});
5860

61+
afterEach(async () => {
62+
await resetMouse();
63+
});
64+
5965
describe('drag and drop', () => {
6066
it('should reorder the widgets while dragging (start -> end)', async () => {
6167
// Start dragging the first widget
@@ -204,6 +210,37 @@ describe('dashboard - widget reordering', () => {
204210
]);
205211
});
206212

213+
// The sendMouse helper does not seem to work well with Firefox
214+
(isFirefox ? it.skip : it)('should reorder using native DnD', async () => {
215+
const spy = sinon.spy();
216+
dashboard.addEventListener('dashboard-item-selected-changed', spy);
217+
await resetMouse();
218+
// Hover over the widget drag handle
219+
await hover(getDraggable(getElementFromCell(dashboard, 0, 0)!));
220+
// Press down the left mouse button
221+
await sendMouse({
222+
type: 'down',
223+
});
224+
// Move the mouse to the second widget
225+
const secondWidget = getElementFromCell(dashboard, 0, 1)!;
226+
const secondWidgetRect = secondWidget.getBoundingClientRect();
227+
const y = secondWidgetRect.top + secondWidgetRect.height / 2;
228+
const x = document.dir === 'rtl' ? secondWidgetRect.left + 1 : secondWidgetRect.right - 1;
229+
await sendMouse({ type: 'move', position: [Math.round(x), Math.round(y)] });
230+
231+
// Release the left mouse button
232+
await sendMouse({ type: 'up' });
233+
234+
// Expect the widgets to be reordered
235+
// prettier-ignore
236+
expectLayout(dashboard, [
237+
[1, 0],
238+
]);
239+
240+
// Expect dashboard-item-selected-changed not to be fired
241+
expect(spy).to.not.have.been.called;
242+
});
243+
207244
it('should not throw with a lazy renderer while reordering', async () => {
208245
// Assign a renderer that initially renders nothing
209246
const syncRenderer = dashboard.renderer!;

0 commit comments

Comments
 (0)