Commit 7dcf2744 authored by Thomas Randolph's avatar Thomas Randolph Committed by Phil Hughes

Attach user popovers to DOM nodes added after the initial DOM query

parent 2595e7a6
...@@ -59,11 +59,33 @@ const populateUserInfo = (user) => { ...@@ -59,11 +59,33 @@ const populateUserInfo = (user) => {
}; };
const initializedPopovers = new Map(); const initializedPopovers = new Map();
let domObservedForChanges = false;
export default (elements = document.querySelectorAll('.js-user-link')) => { const addPopoversToModifiedTree = new MutationObserver(() => {
const userLinks = document?.querySelectorAll('.js-user-link, .gfm-project_member');
if (userLinks) {
addPopovers(userLinks); /* eslint-disable-line no-use-before-define */
}
});
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 userLinks = Array.from(elements);
const UserPopoverComponent = Vue.extend(UserPopover); const UserPopoverComponent = Vue.extend(UserPopover);
observeBody();
return userLinks return userLinks
.filter(({ dataset }) => dataset.user || dataset.userId) .filter(({ dataset }) => dataset.user || dataset.userId)
.map((el) => { .map((el) => {
...@@ -105,4 +127,4 @@ export default (elements = document.querySelectorAll('.js-user-link')) => { ...@@ -105,4 +127,4 @@ export default (elements = document.querySelectorAll('.js-user-link')) => {
return renderedPopover; return renderedPopover;
}); });
}; }
---
title: React to new DOM nodes being added to the page to bind the user information
popover to them
merge_request: 54411
author:
type: fixed
...@@ -6,6 +6,19 @@ describe('User Popovers', () => { ...@@ -6,6 +6,19 @@ describe('User Popovers', () => {
preloadFixtures(fixtureTemplate); preloadFixtures(fixtureTemplate);
const selector = '.js-user-link, .gfm-project_member'; const selector = '.js-user-link, .gfm-project_member';
const findFixtureLinks = () => {
return Array.from(document.querySelectorAll(selector)).filter(
({ dataset }) => dataset.user || dataset.userId,
);
};
const createUserLink = () => {
const link = document.createElement('a');
link.classList.add('js-user-link');
link.setAttribute('data-user', '1');
return link;
};
const dummyUser = { name: 'root' }; const dummyUser = { name: 'root' };
const dummyUserStatus = { message: 'active' }; const dummyUserStatus = { message: 'active' };
...@@ -37,13 +50,20 @@ describe('User Popovers', () => { ...@@ -37,13 +50,20 @@ describe('User Popovers', () => {
}); });
it('initializes a popover for each user link with a user id', () => { it('initializes a popover for each user link with a user id', () => {
const linksWithUsers = Array.from(document.querySelectorAll(selector)).filter( const linksWithUsers = findFixtureLinks();
({ dataset }) => dataset.user || dataset.userId,
);
expect(linksWithUsers.length).toBe(popovers.length); expect(linksWithUsers.length).toBe(popovers.length);
}); });
it('adds popovers to user links added to the DOM tree after the initial call', async () => {
document.body.appendChild(createUserLink());
document.body.appendChild(createUserLink());
const linksWithUsers = findFixtureLinks();
expect(linksWithUsers.length).toBe(popovers.length + 2);
});
it('does not initialize the user popovers twice for the same element', () => { it('does not initialize the user popovers twice for the same element', () => {
const newPopovers = initUserPopovers(document.querySelectorAll(selector)); const newPopovers = initUserPopovers(document.querySelectorAll(selector));
const samePopovers = popovers.every((popover, index) => newPopovers[index] === popover); const samePopovers = popovers.every((popover, index) => newPopovers[index] === popover);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment