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
|
import Vue from 'vue';
import UsersCache from './lib/utils/users_cache';
import UserPopover from './vue_shared/components/user_popover/user_popover.vue';
let renderedPopover;
let renderFn;
const handleUserPopoverMouseOut = event => {
const { target } = event;
target.removeEventListener('mouseleave', handleUserPopoverMouseOut);
if (renderFn) {
clearTimeout(renderFn);
}
if (renderedPopover) {
renderedPopover.$destroy();
renderedPopover = null;
}
target.removeAttribute('aria-describedby');
};
/**
* Adds a UserPopover component to the body, hands over as much data as the target element has in data attributes.
* loads based on data-user-id more data about a user from the API and sets it on the popover
*/
const handleUserPopoverMouseOver = event => {
const { target } = event;
// Add listener to actually remove it again
target.addEventListener('mouseleave', handleUserPopoverMouseOut);
renderFn = setTimeout(() => {
// Helps us to use current markdown setup without maybe breaking or duplicating for now
if (target.dataset.user) {
target.dataset.userId = target.dataset.user;
// Removing titles so its not showing tooltips also
target.dataset.originalTitle = '';
target.setAttribute('title', '');
}
const { userId, username, name, avatarUrl } = target.dataset;
const user = {
userId,
username,
name,
avatarUrl,
location: null,
bio: null,
organization: null,
status: null,
loaded: false,
};
if (userId || username) {
const UserPopoverComponent = Vue.extend(UserPopover);
renderedPopover = new UserPopoverComponent({
propsData: {
target,
user,
},
});
renderedPopover.$mount();
UsersCache.retrieveById(userId)
.then(userData => {
if (!userData) {
return undefined;
}
Object.assign(user, {
avatarUrl: userData.avatar_url,
username: userData.username,
name: userData.name,
location: userData.location,
bio: userData.bio,
organization: userData.organization,
status: userData.status,
loaded: true,
});
if (userData.status) {
return Promise.resolve();
}
return UsersCache.retrieveStatusById(userId);
})
.then(status => {
if (!status) {
return;
}
Object.assign(user, {
status,
});
})
.catch(() => {
renderedPopover.$destroy();
renderedPopover = null;
});
}
}, 200); // 200ms delay so not every mouseover triggers Popover + API Call
};
export default elements => {
const userLinks = elements || [...document.querySelectorAll('.js-user-link')];
userLinks.forEach(el => {
el.addEventListener('mouseenter', handleUserPopoverMouseOver);
});
};
|