docbrown/app/javascript/previewCards/feedPreviewCards.jsx
Jeferson S. Brito 012e625c7c
Add Preact root fragment implementation replacement for replaceNode (#19673)
* feat: add preat-root-fragment implementation of replaceNode

* refact: replace render third argument with root fragment

* chore: reorder preact root imports

* fix: root createRootFragment implementation

* chore: fix base.jsx import order

* fix: add specs for preact-root-fragment

* fix: test ci audit issues

* fix: add insert/append methods specs for root-fragment
2023-07-25 10:11:41 -04:00

119 lines
3.7 KiB
JavaScript

import { h, render } from 'preact';
import { UserMetadata } from '../profilePreviewCards/UserMetadata';
import { createRootFragment } from '../shared/preact/preact-root-fragment';
import {
initializeDropdown,
getDropdownRepositionListener,
} from '@utilities/dropdownUtils';
import { request } from '@utilities/http/request';
const cachedAuthorMetadata = {};
async function populateMissingMetadata(metadataPlaceholder) {
const { authorId, fetched } = metadataPlaceholder.dataset;
// If the metadata is already being fetched, do nothing
if (fetched) {
return;
}
metadataPlaceholder.dataset.fetched = 'true';
const previouslyFetchedAuthorMetadata = cachedAuthorMetadata[authorId];
if (previouslyFetchedAuthorMetadata) {
renderMetadata(previouslyFetchedAuthorMetadata, metadataPlaceholder);
} else {
const response = await request(`/profile_preview_cards/${authorId}`);
const authorMetadata = await response.json();
cachedAuthorMetadata[authorId] = authorMetadata;
renderMetadata(authorMetadata, metadataPlaceholder);
}
}
function renderMetadata(metadata, placeholder) {
const container = placeholder.parentElement;
render(
<UserMetadata {...metadata} />,
createRootFragment(container, placeholder),
);
container
.closest('.profile-preview-card__content')
.style.setProperty('--card-color', metadata.card_color);
}
function checkForPreviewCardDetails(event) {
const { target } = event;
if (target.classList.contains('profile-preview-card__trigger')) {
const metadataPlaceholder = target.parentElement.getElementsByClassName(
'author-preview-metadata-container',
)[0];
if (metadataPlaceholder) {
// User is within one of the story cards - and the metadata has not been fetched yet
populateMissingMetadata(metadataPlaceholder);
}
}
}
export function listenForHoveredOrFocusedStoryCards() {
const mainContent = document.getElementById('main-content');
mainContent.addEventListener('mouseover', checkForPreviewCardDetails);
mainContent.addEventListener('focusin', checkForPreviewCardDetails);
}
export function initializeFeedPreviewCards() {
// Select all preview card triggers that haven't already been initialized
const allPreviewCardTriggers = document.querySelectorAll(
'button[id^=story-author-preview-trigger]:not([data-initialized])',
);
for (const previewTrigger of allPreviewCardTriggers) {
const dropdownContentId = previewTrigger.getAttribute('aria-controls');
const dropdownElement = document.getElementById(dropdownContentId);
if (dropdownElement) {
initializeDropdown({
triggerElementId: previewTrigger.id,
dropdownContentId,
onOpen: () => dropdownElement?.classList.add('showing'),
onClose: () => dropdownElement?.classList.remove('showing'),
});
previewTrigger.dataset.initialized = true;
}
}
}
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.type === 'childList') {
initializeFeedPreviewCards();
}
});
});
if (document.getElementById('index-container')) {
observer.observe(document.getElementById('index-container'), {
childList: true,
subtree: true,
});
}
// Preview card dropdowns reposition on scroll
const dropdownRepositionListener = getDropdownRepositionListener();
document.addEventListener('scroll', dropdownRepositionListener);
InstantClick.on('change', () => {
observer.disconnect();
document.removeEventListener('scroll', dropdownRepositionListener);
});
window.addEventListener('beforeunload', () => {
observer.disconnect();
document.removeEventListener('scroll', dropdownRepositionListener);
});