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.js121
1 files changed, 72 insertions, 49 deletions
diff --git a/app/assets/javascripts/user_popovers.js b/app/assets/javascripts/user_popovers.js
index 4544373d8aa..597b96ae18c 100644
--- a/app/assets/javascripts/user_popovers.js
+++ b/app/assets/javascripts/user_popovers.js
@@ -57,41 +57,35 @@ const populateUserInfo = (user) => {
);
};
-const initializedPopovers = new Map();
-let domObservedForChanges = false;
+function initPopover(el, user, mountPopover) {
+ 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);
}
-});
-
-function observeBody() {
- if (!domObservedForChanges) {
- addPopoversToModifiedTree.observe(document.body, {
- subtree: true,
- childList: true,
- });
-
- domObservedForChanges = true;
- }
-}
-
-export default function addPopovers(elements = document.querySelectorAll('.js-user-link')) {
- const userLinks = Array.from(elements);
const UserPopoverComponent = Vue.extend(UserPopover);
+ const popoverInstance = new UserPopoverComponent({
+ propsData: {
+ target: el,
+ user,
+ },
+ });
+ mountPopover(popoverInstance);
+ // wait for component to actually mount
+ setTimeout(() => {
+ // trigger an event to force tooltip to show
+ const event = new MouseEvent('mouseenter');
+ event.isSelfTriggered = true;
+ el.dispatchEvent(event);
+ });
+}
- observeBody();
-
- return userLinks
- .filter(({ dataset }) => dataset.user || dataset.userId)
- .map((el) => {
- if (initializedPopovers.has(el)) {
- return initializedPopovers.get(el);
- }
-
+function initPopovers(userLinks, mountPopover) {
+ userLinks
+ .filter(({ dataset, user }) => !user && (dataset.user || dataset.userId))
+ .forEach((el) => {
const user = {
location: null,
bio: null,
@@ -99,31 +93,60 @@ export default function addPopovers(elements = document.querySelectorAll('.js-us
status: null,
loaded: false,
};
- const renderedPopover = new UserPopoverComponent({
- propsData: {
- target: el,
- user,
- },
+ el.user = user;
+ const init = initPopover.bind(null, el, user, mountPopover);
+ el.addEventListener('mouseenter', init, { once: true });
+ el.addEventListener('mouseenter', ({ target, isSelfTriggered }) => {
+ if (!isSelfTriggered) return;
+ removeTitle(target);
});
+ el.addEventListener('mouseleave', ({ target }) => {
+ target.removeAttribute('aria-describedby');
+ });
+ });
+}
- initializedPopovers.set(el, renderedPopover);
+const userLinkSelector = 'a.js-user-link, a.gfm-project_member';
- renderedPopover.$mount();
+const getUserLinkNodes = (node) => {
+ if (!('matches' in node)) return null;
+ if (node.matches(userLinkSelector)) return [node];
+ return Array.from(node.querySelectorAll(userLinkSelector));
+};
- el.addEventListener('mouseenter', ({ target }) => {
- removeTitle(target);
- const preloadedUserInfo = getPreloadedUserInfo(target.dataset);
+let observer;
- Object.assign(user, preloadedUserInfo);
+export default function addPopovers(
+ elements = document.querySelectorAll('.js-user-link'),
+ mountPopover = (popoverInstance) => popoverInstance.$mount(),
+) {
+ const userLinks = Array.from(elements);
- if (preloadedUserInfo.userId) {
- populateUserInfo(user);
- }
- });
- el.addEventListener('mouseleave', ({ target }) => {
- target.removeAttribute('aria-describedby');
- });
+ initPopovers(userLinks, mountPopover);
+
+ if (!observer) {
+ observer = new MutationObserver((mutationsList) => {
+ const newUserLinks = mutationsList
+ .filter((mutation) => mutation.type === 'childList' && mutation.addedNodes)
+ .reduce((acc, mutation) => {
+ const userLinkNodes = Array.from(mutation.addedNodes)
+ .flatMap(getUserLinkNodes)
+ .filter(Boolean);
+ acc.push(...userLinkNodes);
+ return acc;
+ }, []);
+
+ if (newUserLinks.length !== 0) {
+ initPopovers(newUserLinks, mountPopover);
+ }
+ });
+ observer.observe(document.body, {
+ subtree: true,
+ childList: true,
+ });
- return renderedPopover;
+ document.addEventListener('beforeunload', () => {
+ observer.disconnect();
});
+ }
}