summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-29 15:09:53 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-29 15:09:53 +0000
commit9c28b22cfc7b2b9306b9c72d53f5c88c3129eb67 (patch)
tree92e5e3ac55cfa092d473abca506546cf56e2215c /app/assets/javascripts
parentef59e05bd14aea8bf19bbe77c52116bfe24c7107 (diff)
downloadgitlab-ce-9c28b22cfc7b2b9306b9c72d53f5c88c3129eb67.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js2
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue7
-rw-r--r--app/assets/javascripts/flash.js4
-rw-r--r--app/assets/javascripts/members/components/table/members_table.vue4
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue2
-rw-r--r--app/assets/javascripts/user_popovers.js121
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue2
7 files changed, 74 insertions, 68 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index c4e09efe263..4bfce12c7c5 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -1,6 +1,5 @@
import $ from 'jquery';
import syntaxHighlight from '~/syntax_highlight';
-import initUserPopovers from '../../user_popovers';
import highlightCurrentUser from './highlight_current_user';
import renderMath from './render_math';
import renderMermaid from './render_mermaid';
@@ -20,7 +19,6 @@ $.fn.renderGFM = function renderGFM() {
renderMermaid(this.find('.js-render-mermaid'));
}
highlightCurrentUser(this.find('.gfm-project_member').get());
- initUserPopovers(this.find('.js-user-link').get());
const mrPopoverElements = this.find('.gfm-merge_request').get();
if (mrPopoverElements.length) {
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index ba10f6deb29..8d0f6079f8f 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -7,8 +7,6 @@ import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import initUserPopovers from '../../user_popovers';
-
/**
* CommitItem
*
@@ -82,11 +80,6 @@ export default {
return this.commit.description_html.replace(/^&#x000A;/, '');
},
},
- created() {
- this.$nextTick(() => {
- initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
- });
- },
safeHtmlConfig: {
ADD_TAGS: ['gl-emoji'],
},
diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js
index fa605f8c056..24ec16bf20e 100644
--- a/app/assets/javascripts/flash.js
+++ b/app/assets/javascripts/flash.js
@@ -94,10 +94,10 @@ const addDismissFlashClickListener = (flashEl, fadeTransition) => {
*
* 1. Render a new alert
*
- * import { createAlert, ALERT_VARIANTS } from '~/flash';
+ * import { createAlert, VARIANT_WARNING } from '~/flash';
*
* createAlert({ message: 'My error message' });
- * createAlert({ message: 'My warning message', variant: ALERT_VARIANTS.WARNING });
+ * createAlert({ message: 'My warning message', variant: VARIANT_WARNING });
*
* 2. Dismiss this alert programmatically
*
diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue
index 0b97ce7e33e..660fbd79fe3 100644
--- a/app/assets/javascripts/members/components/table/members_table.vue
+++ b/app/assets/javascripts/members/components/table/members_table.vue
@@ -4,7 +4,6 @@ import { mapState } from 'vuex';
import MembersTableCell from 'ee_else_ce/members/components/table/members_table_cell.vue';
import { canOverride, canRemove, canResend, canUpdate } from 'ee_else_ce/members/utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
-import initUserPopovers from '~/user_popovers';
import UserDate from '~/vue_shared/components/user_date.vue';
import {
FIELD_KEY_ACTIONS,
@@ -85,9 +84,6 @@ export default {
return this.tabQueryParamValue === TAB_QUERY_PARAM_VALUES.invite;
},
},
- mounted() {
- initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
- },
methods: {
hasActionButtons(member) {
return (
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index c4924cd41f5..c8af3c744e8 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -3,7 +3,6 @@ import { mapGetters, mapActions } from 'vuex';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
import createFlash from '~/flash';
import { __ } from '~/locale';
-import initUserPopovers from '~/user_popovers';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import OrderedLayout from '~/vue_shared/components/ordered_layout.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -169,7 +168,6 @@ export default {
updated() {
this.$nextTick(() => {
highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member'));
- initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
});
},
beforeDestroy() {
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();
});
+ }
}
diff --git a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
index d595c49f9aa..5f6490a9f3f 100644
--- a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
+++ b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
@@ -18,7 +18,6 @@ import { toggleContainerClasses } from '~/lib/utils/dom_utils';
import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
-import initUserPopovers from '~/user_popovers';
import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { PAGE_CONFIG, SEVERITY_LEVELS } from '../constants';
@@ -175,7 +174,6 @@ export default {
updated() {
this.$nextTick(() => {
highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member'));
- initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
});
},
methods: {