Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/user_popovers.js')
-rw-r--r--app/assets/javascripts/user_popovers.js139
1 files changed, 66 insertions, 73 deletions
diff --git a/app/assets/javascripts/user_popovers.js b/app/assets/javascripts/user_popovers.js
index 438ae2bc1bc..a3615eab26f 100644
--- a/app/assets/javascripts/user_popovers.js
+++ b/app/assets/javascripts/user_popovers.js
@@ -1,6 +1,8 @@
import Vue from 'vue';
+import { debounce } from 'lodash';
import UsersCache from './lib/utils/users_cache';
import UserPopover from './vue_shared/components/user_popover/user_popover.vue';
+import { USER_POPOVER_DELAY } from './vue_shared/components/user_popover/constants';
const removeTitle = (el) => {
// Removing titles so its not showing tooltips also
@@ -59,87 +61,78 @@ const populateUserInfo = (user) => {
);
};
-const initializedPopovers = new Map();
-let domObservedForChanges = false;
+function createPopover(el, user) {
+ removeTitle(el);
+ const preloadedUserInfo = getPreloadedUserInfo(el.dataset);
-const addPopoversToModifiedTree = new MutationObserver(() => {
- const userLinks = document?.querySelectorAll('.js-user-link, .gfm-project_member');
+ Object.assign(user, preloadedUserInfo);
- if (userLinks) {
- addPopovers(userLinks); /* eslint-disable-line no-use-before-define */
+ if (preloadedUserInfo.userId) {
+ populateUserInfo(user);
}
-});
+ const UserPopoverComponent = Vue.extend(UserPopover);
+ return new UserPopoverComponent({
+ propsData: {
+ target: el,
+ user,
+ show: true,
+ placement: el.dataset.placement || 'top',
+ },
+ });
+}
-function observeBody() {
- if (!domObservedForChanges) {
- addPopoversToModifiedTree.observe(document.body, {
- subtree: true,
- childList: true,
- });
+function launchPopover(el, mountPopover) {
+ if (el.user) return;
- domObservedForChanges = true;
- }
+ const emptyUser = {
+ location: null,
+ bio: null,
+ workInformation: null,
+ status: null,
+ isFollowed: false,
+ loaded: false,
+ };
+ el.user = emptyUser;
+ el.addEventListener(
+ 'mouseleave',
+ ({ target }) => {
+ target.removeAttribute('aria-describedby');
+ },
+ { once: true },
+ );
+ const popoverInstance = createPopover(el, emptyUser);
+
+ const { userId } = el.dataset;
+
+ popoverInstance.$on('follow', () => {
+ UsersCache.updateById(userId, { is_followed: true });
+ el.user.isFollowed = true;
+ });
+
+ popoverInstance.$on('unfollow', () => {
+ UsersCache.updateById(userId, { is_followed: false });
+ el.user.isFollowed = false;
+ });
+
+ mountPopover(popoverInstance);
}
-export default function addPopovers(elements = document.querySelectorAll('.js-user-link')) {
- const userLinks = Array.from(elements);
- const UserPopoverComponent = Vue.extend(UserPopover);
+const userLinkSelector = 'a.js-user-link, a.gfm-project_member';
- observeBody();
+const getUserLinkNode = (node) => node.closest(userLinkSelector);
- return userLinks
- .filter(({ dataset }) => dataset.user || dataset.userId)
- .map((el) => {
- if (initializedPopovers.has(el)) {
- return initializedPopovers.get(el);
- }
+const lazyLaunchPopover = debounce((mountPopover, event) => {
+ const userLink = getUserLinkNode(event.target);
+ if (userLink) {
+ launchPopover(userLink, mountPopover);
+ }
+}, USER_POPOVER_DELAY);
- const user = {
- location: null,
- bio: null,
- workInformation: null,
- status: null,
- isFollowed: false,
- loaded: false,
- };
- const renderedPopover = new UserPopoverComponent({
- propsData: {
- target: el,
- user,
- placement: el.dataset.placement || 'top',
- },
- });
-
- const { userId } = el.dataset;
-
- renderedPopover.$on('follow', () => {
- UsersCache.updateById(userId, { is_followed: true });
- user.isFollowed = true;
- });
-
- renderedPopover.$on('unfollow', () => {
- UsersCache.updateById(userId, { is_followed: false });
- user.isFollowed = false;
- });
-
- initializedPopovers.set(el, renderedPopover);
-
- renderedPopover.$mount();
-
- el.addEventListener('mouseenter', ({ target }) => {
- removeTitle(target);
- const preloadedUserInfo = getPreloadedUserInfo(target.dataset);
-
- Object.assign(user, preloadedUserInfo);
-
- if (preloadedUserInfo.userId) {
- populateUserInfo(user);
- }
- });
- el.addEventListener('mouseleave', ({ target }) => {
- target.removeAttribute('aria-describedby');
- });
-
- return renderedPopover;
- });
+let hasAddedLazyPopovers = false;
+
+export default function addPopovers(mountPopover = (instance) => instance.$mount()) {
+ if (!hasAddedLazyPopovers) {
+ document.addEventListener('mouseover', (event) => lazyLaunchPopover(mountPopover, event));
+ hasAddedLazyPopovers = true;
+ }
}