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
|
/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
import { DirectiveBinding } from 'vue';
interface FocusAnywhereButHereArgs {
blur: () => void,
isMouseDown?: boolean;
hasScrolled?: boolean;
onEscapeHandler?: (event: KeyboardEvent) => void;
onMouseDown?: () => void;
onClickOutsideElement?: (event: MouseEvent) => void;
onScroll?: () => void;
}
function onClickOutsideElement(
element: HTMLElement,
binding: DirectiveBinding<FocusAnywhereButHereArgs>,
event: MouseEvent,
) {
const hadUsedScrollbar = binding.value.isMouseDown && binding.value.hasScrolled;
binding.value.isMouseDown = false;
binding.value.hasScrolled = false;
if (hadUsedScrollbar) {
return;
}
if (!element.contains(event.target as HTMLElement)) {
if (binding.value) {
binding.value.blur();
}
}
}
function onScroll(element: HTMLElement, binding: DirectiveBinding<FocusAnywhereButHereArgs>) {
binding.value.hasScrolled = true;
}
function onMouseDown(element: HTMLElement, binding: DirectiveBinding<FocusAnywhereButHereArgs>) {
binding.value.isMouseDown = true;
binding.value.hasScrolled = false;
}
function onEscapeHandler(
element: HTMLElement,
binding: DirectiveBinding<FocusAnywhereButHereArgs>,
event: KeyboardEvent,
) {
if (event.which === 27) {
setTimeout(() => {
binding.value.isMouseDown = false;
binding.value.hasScrolled = false;
if (binding.value.blur) {
binding.value.blur();
}
}, 0);
}
}
const doc = document.documentElement;
/**
* Usage (in a component):
*
* directives: {
* // function call is important since we store state in this directive
* FocusAnywhereButHere: FocusAnywhereButHere(),
* }
*
* Note: the binding data needs to be static, changes will not be handled.
*/
export default {
mounted(el: HTMLElement, binding: DirectiveBinding<FocusAnywhereButHereArgs>): void {
binding.value.isMouseDown = false;
binding.value.hasScrolled = false;
binding.value.onEscapeHandler = onEscapeHandler.bind(null, el, binding);
binding.value.onMouseDown = onMouseDown.bind(null, el, binding);
binding.value.onClickOutsideElement = onClickOutsideElement.bind(null, el, binding);
binding.value.onScroll = onScroll.bind(null, el, binding);
doc.addEventListener('keyup', binding.value.onEscapeHandler);
doc.addEventListener('mousedown', binding.value.onMouseDown);
doc.addEventListener('mouseup', binding.value.onClickOutsideElement);
doc.addEventListener('scroll', binding.value.onScroll);
},
unmounted(el: HTMLElement, binding: DirectiveBinding<FocusAnywhereButHereArgs>): void {
doc.removeEventListener('keyup', binding.value.onEscapeHandler);
doc.removeEventListener('mousedown', binding.value.onMouseDown);
doc.removeEventListener('mouseup', binding.value.onClickOutsideElement);
doc.removeEventListener('scroll', binding.value.onScroll);
},
};
|