* 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
119 lines
3.7 KiB
JavaScript
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);
|
|
});
|